*** empty log message ***
[m17n/m17n-lib-cs.git] / MText.cs
1 using System;
2 using System.Text;
3 using System.Collections;
4 using System.Collections.Generic;
5 using M17N;
6 using M17N.Core;
7
8 namespace M17N.Core
9 {
10 #if false
11   public enum MTextFormat
12     {
13       MTEXT_FORMAT_US_ASCII,
14       MTEXT_FORMAT_UTF_8,
15       MTEXT_FORMAT_UTF_16BE,
16       MTEXT_FORMAT_UTF_16LE,
17       MTEXT_FORMAT_UTF_32BE,
18       MTEXT_FORMAT_UTF_32LE,
19     }
20 #endif
21
22   public class MTextProperty
23   {
24     internal MSymbol key;
25     internal object val;
26
27     [FlagsAttribute]
28     internal enum Flag : byte
29       {
30         None =          0,
31         FrontSticky =   1,
32         RearSticky =    2,
33         Sensitive =     4
34       };
35     internal Flag flags;
36
37     public MSymbol Key { get { return key; } }
38     public object Val { get { return val; } }
39     public bool FrontSticky
40     {
41       get { return (flags & Flag.FrontSticky) != Flag.None; }
42     }
43     public bool RearSticky
44     {
45       get { return (flags & Flag.RearSticky) != Flag.None; }
46     }
47     public bool Sensitive
48     {
49       get { return (flags & Flag.Sensitive) != Flag.None; }
50     }
51
52     public MTextProperty (MSymbol key, object val)
53     {
54       this.key = key;
55       this.val = val;
56       flags |= Flag.RearSticky;
57     }
58
59     public MTextProperty (MSymbol key, object val,
60                           bool front_sticky, bool rear_sticky, bool sensitive)
61     {
62       this.key = key;
63       this.val = val;
64       if (front_sticky)
65         flags |= Flag.FrontSticky;
66       if (rear_sticky)
67         flags |= Flag.RearSticky;
68       if (sensitive)
69         flags |= Flag.Sensitive;
70     }
71
72     public override string ToString ()
73     {
74       return key.ToString () + ":" + val;
75     }
76   }
77
78   public class MText : IEnumerable, IEquatable<MText>, IComparable<MText>
79   {
80 #if false
81     public enum MTextFormat format;
82 #endif
83     private StringBuilder sb;
84     private int nchars;
85     private int cache_pos;
86     private int cache_idx;
87     private MPlist intervals;
88     private MPlist default_property;
89     private bool read_only;
90
91     private static UTF8Encoding utf8 = new UTF8Encoding ();
92
93     private static int count_chars (String str)
94     {
95       int len = str.Length, n = 0;
96
97       for (int i = 0; i < len; i++, n++) 
98         if (surrogate_high_p (str[i]))
99           i++;
100       return n;
101     }
102
103     private static int count_chars (StringBuilder str)
104     {
105       int len = str.Length, n = 0;
106
107       for (int i = 0; i < len; i++, n++) 
108         if (surrogate_high_p (str[i]))
109           i++;
110       return n;
111     }
112
113     public MText ()
114       {
115         sb = new StringBuilder ();
116         intervals = new MPlist ();
117       }
118
119     public MText (byte[] str)
120       {
121         sb = new StringBuilder (utf8.GetString (str));
122         nchars = count_chars (sb);
123         intervals = new MPlist ();
124       }
125
126     public MText (String str)
127       {
128         sb = new StringBuilder (str);
129         nchars = count_chars (str);
130         intervals = new MPlist ();
131       }
132
133     public MText (StringBuilder str)
134       {
135         sb = str;
136         nchars = count_chars (str);
137         intervals = new MPlist ();
138       }
139
140     public static MText operator+ (MText mt1, MText mt2)
141     {
142       MText mt = new MText ();
143
144       mt.sb.Append (mt1.sb);
145       mt.sb.Append (mt2.sb);
146       mt.nchars = mt1.nchars + mt2.nchars;
147       return mt;
148     }
149
150     // Public properties
151     public bool ReadOnly { get { return read_only; } }
152     public int Length { get { return nchars; } }
153
154     // Public methods
155
156     // for IEnumerable interface
157     public IEnumerator GetEnumerator() { return new MTextEnum (this); }
158
159     // for IEquatable interface
160     public bool Equals (MText other) { return this.sb.Equals (other.sb); }
161
162     // for IComparable interface
163     public int CompareTo (MText other)
164     {
165       return this.sb.ToString ().CompareTo (other.sb.ToString ());
166     }
167
168     public override String ToString () { return "\"" + sb.ToString () + "\""; }
169
170     private static bool surrogate_high_p (char c)
171     {
172       return (c >= 0xD800 && c < 0xDC00);
173     }
174
175     private static bool surrogate_low_p (char c)
176     {
177       return (c >= 0xDC00 && c < 0xE000);
178     }
179
180     private static int inc_idx (StringBuilder sb, int i)
181     {
182       return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
183     }
184
185     private static int dec_idx (StringBuilder sb, int i)
186     {
187       return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
188     }
189
190     private static int pos_to_idx (MText mt, int pos)
191     {
192       if (pos == mt.cache_pos)
193         return mt.cache_idx;
194
195       int p, i;
196       bool forward;
197
198       if (pos < mt.cache_pos)
199         {
200           if (mt.cache_pos == mt.cache_idx)
201             return mt.cache_idx;
202           if (pos < mt.cache_pos - pos)
203             {
204               p = i = 0;
205               forward = true;
206             }
207           else
208             {
209               p = mt.cache_pos; i = mt.cache_idx;
210               forward = false;
211             }
212         }
213       else
214         {
215           if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
216             return (mt.cache_idx + pos - mt.cache_pos);
217           if (pos - mt.cache_pos < mt.nchars - pos)
218             {
219               p = mt.cache_pos; i = mt.cache_idx;
220               forward = true;
221             }
222           else
223             {
224               p = mt.nchars; i = mt.sb.Length;
225               forward = false;
226             }
227         }
228       if (forward)
229         for (; p < pos; i = inc_idx (mt.sb, i), p++);
230       else
231         for (; p > pos; i = dec_idx (mt.sb, i), p--);
232       mt.cache_pos = p;
233       mt.cache_idx = i;
234       return i;
235     }
236
237     private void check_pos (int pos, bool tail_ok)
238     {
239       if (pos < 0 || (tail_ok ? pos > nchars : pos >= nchars))
240         throw new Exception ("Invalid MText position:" + pos);
241     }
242
243     private bool check_range (int from, int to, bool zero_ok)
244     {
245       if (from < 0 || (zero_ok ? from > to : from >= to)
246           || to > nchars)
247         throw new Exception ("Invalid MText range");
248       return (from == to);
249     }
250
251     private void insert (int pos, MText mt2, int from, int to)
252     {
253       check_pos (pos, true);
254
255       int pos_idx = pos_to_idx (this, pos);
256       int from_idx = pos_to_idx (mt2, from);
257       int to_idx = pos_to_idx (mt2, to);
258
259       sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
260       nchars += to - from;
261
262       foreach (MPlist plist in mt2.intervals)
263         if (intervals.Find (plist.Key) == null)
264           intervals.Push (plist.Key, new MInterval (plist.Key, this));
265       foreach (MPlist plist in intervals)
266         {
267           MPlist p = mt2.intervals.Find (plist.Key);
268           MInterval interval;
269
270           if (p == null)
271             interval = new MInterval (plist.Key, this, to - from);
272           else
273             interval = ((MInterval) p.Val).Copy (from, to);
274           ((MInterval) plist.Val).Insert (pos, interval);
275         }
276     }
277
278     private void insert (int pos, int c)
279     {
280       check_pos (pos, true);
281
282       int pos_idx = pos_to_idx (this, pos);
283
284       if (c < 0x10000)
285         {
286           char ch = (char) c;
287           sb.Insert (pos_idx, ch);
288         }
289       else
290         {
291           char high = (char) (0xD800 + ((c - 0x10000) >> 10));
292           char low = (char) (0xDC00 + ((c - 0x10000) & 0x3FF));
293           sb.Insert (pos_idx, low);
294           sb.Insert (pos_idx, high);
295         }
296       nchars++;
297       foreach (MPlist plist in intervals)
298         ((MInterval) plist.Val).Insert (pos,
299                                         new MInterval (plist.Key, this, 1));
300     }
301
302     public int this[int i]
303     {
304       set {
305         i = pos_to_idx (this, i);
306         if (value < 0x10000)
307           {
308             if (surrogate_high_p (sb[i]))
309               sb.Remove (i, 1);
310             sb[i] = (char) value;
311           }
312         else
313           {
314             char high = (char) (0xD800 + ((value - 0x10000) >> 10));
315             char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
316
317             if (! surrogate_high_p (sb[i]))
318               sb.Insert (i, 0);
319             sb[i] = high;
320             sb[i + 1] = low;
321           }
322       }
323       get {
324         i = pos_to_idx (this, i);
325         return (surrogate_high_p (sb[i])
326                 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
327                 : sb[i]);
328       }
329     }
330
331     public MText Dup ()
332     {
333       MText mt = new MText (sb.ToString ());
334
335       foreach (MPlist p in intervals)
336         mt.intervals.Add (p.Key, ((MInterval) p.Val).Copy (0, Length));
337       return mt;
338     }
339
340     public MText Ins (int pos, int c)
341     {
342       insert (pos, c);
343       return this;
344     }
345
346     public MText Ins (int pos, MText mt)
347     {
348       insert (pos, mt, 0, mt.nchars);
349       return this;
350     }
351
352     public MText Ins (int pos, MText mt, int from, int to)
353     {
354       insert (pos, mt, from, to);
355       return this;
356     }
357
358     public MText Cat (int c)
359     {
360       insert (nchars, c);
361       return this;
362     }
363
364     public MText Del (int from, int to)
365     {
366       if (check_range (from, to, true))
367         return this;
368
369       sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
370       nchars -= to - from;
371
372       if (nchars > 0)
373         foreach (MPlist plist in intervals)
374           ((MInterval) plist.Val).Delete (from, to);
375       else
376         intervals = new MPlist ();
377       return this;
378     }
379
380     public object GetProp (int pos, MSymbol key)
381     {
382       check_pos (pos, false);
383
384       MInterval i = (MInterval) intervals.Get (key);
385       if (i == null)
386         return null;
387
388       MTextProperty prop = i.Get (pos);
389       return (prop != null ? prop.Val : null);
390     }
391
392     public object GetProp (int pos, MSymbol key, out MTextProperty prop)
393     {
394       check_pos (pos, false);
395
396       MInterval i = (MInterval) intervals.Get (key);
397       if (i == null)
398         return (prop = null);
399       prop = i.Get (pos);
400       return (prop != null ? prop.Val : null);
401     }
402
403     public object GetProp (int pos, MSymbol key, out MTextProperty[] array)
404     {
405       check_pos (pos, false);
406
407       MInterval i = (MInterval) intervals.Get (key);
408       if (i == null)
409         return (array = null);
410       MTextProperty prop = i.Get (pos, out array);
411       return (prop != null ? prop.Val : null);
412     }
413
414     public void PushProp (int from, int to, MSymbol key, object val)
415     {
416       if (! check_range (from, to, true))
417         PushProp (from, to, new MTextProperty (key, val));
418     }
419
420     public void PushProp (int from, int to, MTextProperty prop)
421     {
422       if (from < 0)
423         {
424           if (default_property == null)
425             default_property = new MPlist ();
426           default_property.Push (prop.key, prop.val);
427         }
428       else
429         {
430           if (check_range (from, to, true))
431             return;
432
433           MPlist p = intervals.Find (prop.key);
434           MInterval root;
435
436           if (p == null)
437             {
438               root = new MInterval (prop.key, this);
439               intervals.Push (prop.key, root);
440             }
441           else
442             root = (MInterval) p.Val;
443
444           root.Push (from, to, prop);
445         }
446     }
447
448     public void PopProp (int from, int to, MSymbol key)
449     {
450       if (from < 0)
451         {
452           if (default_property == null)
453             return;
454           MPlist p = default_property.Find (key);
455
456           if (p != null)
457             p.Pop ();
458         }
459       else
460         {
461           if (check_range (from, to, true))
462             return;
463
464           MPlist p = intervals.Find (key);
465
466           if (p != null)
467             {
468               MInterval root = (MInterval) p.Val;
469               root.Pop (from, to);
470               DumpPropNested ();
471               root.MergeAfterChange (from, to);
472             }
473         }
474     }
475
476     public void DumpProp ()
477     {
478       Console.Write ("(");
479       foreach (MPlist p in intervals)
480         ((MInterval) p.Val).Dump (true);
481       Console.WriteLine (")");
482     }
483
484     public void DumpPropNested ()
485     {
486       foreach (MPlist p in intervals)
487         ((MInterval) p.Val).DumpNested (true);
488     }
489
490     private class MInterval
491     {
492       // position: 0   1   2   3   4   5   6   7
493       //           | A | B | C | D | E   F | G |
494       // interval  |---|---|---|<->|-------|---|
495       //           |---|<->|---|   |<----->|---|
496       //           |<->|   |<->|           |<->|
497       // 
498       //                      [7 (3 4)]
499       //              [3 (1 2)]       [3 (4 6)]
500       //         [1 (0 1)] [2 (2 3)]      [1 (6 7)]
501       //
502       private static int count = 0;
503       private int ID;
504       private int Length;
505       private int From, To;
506       private MSymbol Key;
507       private MPlist Stack;
508       private MInterval Left, Right, Parent;
509       private MText mtext;
510
511       public MInterval (MSymbol key, MText mt, int length)
512       {
513         if (length <= 0)
514           throw new Exception ("Invalid interval length");
515         Key = key;
516         mtext = mt;
517         Length = length;
518         Stack = new MPlist ();
519         ID = count++;
520       }
521
522       public MInterval (MSymbol key, MText mt)
523       {
524         Key = key;
525         mtext = mt;
526         Length = mt.sb.Length;
527         From = 0;
528         To = Length;
529         Stack = new MPlist ();
530         ID = count++;
531       }
532
533       public MTextProperty Get (int pos)
534       {
535         MInterval i = find (pos);
536
537         return (i.Stack.IsEmpty ? null : (MTextProperty) i.Stack.Val);
538       }
539
540       public MTextProperty Get (int pos, out MTextProperty[] array)
541       {
542         MInterval i = find (pos);
543
544         if (i.Stack.IsEmpty)
545           {
546             array = null;
547             return null;
548           }
549         array = new MTextProperty[i.Stack.Count];
550
551         int idx;
552         MPlist p;
553         for (idx = 0, p = i.Stack; ! p.IsEmpty; idx++, p = p.Next)
554           array[idx] = (MTextProperty) p.Val;
555         return array[0];
556       }
557
558       private MInterval (MSymbol key, MText mt, int length, MPlist stack)
559       {
560         Key = key;
561         mtext = mt;
562         Length = length;
563         From = 0;
564         To = Length;
565         Stack = stack.Clone ();
566         ID = count++;
567       }
568
569       private void update_from_to ()
570       {
571         if (Parent == null)
572           {
573             From = LeftLength;
574             To = Length - RightLength;
575           }
576         else if (Parent.Left == this)
577           {
578             From = Parent.From - Length + LeftLength;
579             To = Parent.From - RightLength;
580           }
581         else
582           {
583             From = Parent.To + LeftLength;
584             To = Parent.To + Length - RightLength;
585           }
586       }
587
588       private int LeftLength
589       {
590         get { return (Left == null ? 0 : Left.Length); }
591       }
592
593       private int RightLength
594       {
595         get { return (Right == null ? 0 : Right.Length); }
596       }
597
598       private MInterval LeftMost
599       {
600         get { return (Left == null ? this : Left.LeftMost); }
601       }
602
603       private MInterval RightMost
604       {
605         get { return (Right == null ? this : Right.RightMost); }
606       }
607
608       private MInterval Prev {
609         get {
610           MInterval i;
611
612           if (Left != null)
613             for (i = Left; i.Right != null; i = i.Right);
614           else
615             {
616               MInterval child = this;
617               for (i = Parent; i != null && i.Left == child;
618                    child = i, i = i.Parent);
619             }
620           return i;
621         }
622       }
623
624       private MInterval Next {
625         get {
626           MInterval i;
627
628           if (Right != null)
629             for (i = Right; i.Left != null; i = i.Left);
630           else
631             {
632               MInterval child = this;
633               for (i = Parent; i != null && i.Right == child;
634                    child = i, i = i.Parent);
635             }
636           return i;
637         }
638       }
639
640       private MInterval find (int pos)
641       {
642         update_from_to ();
643         if (pos < From)
644           return Left.find (pos);
645         if (pos >= To)
646           return Right.find (pos);
647         return this;
648       }
649
650       private bool mergeable (MInterval i)
651       {
652         MPlist p1, p2;
653
654         for (p1 = Stack, p2 = i.Stack; ! p1.IsEmpty && ! p2.IsEmpty;
655              p1 = p1.Next, p2 = p2.Next)
656           if (p1.Val != p2.Val)
657             return false;
658         return (p1.IsEmpty && p2.IsEmpty);
659       }
660
661       //      p-. or .-p              p-. or .-p
662       //       .-this-.                .-right-.
663       //    left   .-right-.  ->   .-this-.    c2
664       //          c1       c2    left     c1
665       private MInterval promote_right ()
666       {
667         int right_length = Right.Length;
668         MInterval c1;
669
670         if (Parent == null)
671           mtext.intervals.Put (Key, Right);
672         else if (Parent.Left == this)
673           Parent.Left = Right;
674         else
675           Parent.Right = Right;
676         Right.Parent = Parent;
677         c1 = Right.Left;
678         Right.Left = this;
679
680         Parent = Right;
681         Right = c1;
682         Parent.Length += Length;
683         Length -= right_length;
684         if (c1 != null)
685           {
686             c1.Parent = this;
687             Parent.Length -= c1.Length;
688             Length += c1.Length;
689           }
690         return Parent;
691       }
692
693       //      p-. or .-p              p-. or .-p
694       //       .-this-.                .-left-.
695       //  .-left-.  .-right-.  ->     c1    .-this-.
696       // c1      c2                        c2     right
697       private MInterval promote_left ()
698       {
699         int left_length = Left.Length;
700         MInterval c1;
701
702         if (Parent == null)
703           mtext.intervals.Put (Key, Left);
704         else if (Parent.Left == this)
705           Parent.Left = Left;
706         else
707           Parent.Right = Left;
708         Left.Parent = Parent;
709         c1 = Left.Left;
710         Left.Right = this;
711
712         Parent = Left;
713         Left = c1;
714         Parent.Length += Length;
715         Length -= left_length;
716         if (c1 != null)
717           {
718             c1.Parent = this;
719             Parent.Length -= c1.Length;
720             Length += c1.Length;
721           }
722         return Parent;
723       }
724
725       private MInterval balance ()
726       {
727         MInterval i = this;
728
729         while (true)
730           {
731             //       .-this-.
732             //  .-left-.  .-right-.
733             // c1     c2  c3      c4
734             int diff = i.LeftLength - i.RightLength;
735             int new_diff;
736
737             if (diff > 0)
738               {
739                 new_diff = (i.Length - i.LeftLength
740                             + i.Left.RightLength - i.Left.LeftLength);
741                 if (Math.Abs (new_diff) >= diff)
742                   break;
743                 i = i.promote_left ();
744                 i.Right.balance ();
745               }
746             else if (diff < 0)
747               {
748                 new_diff = (i.Length - i.RightLength
749                             + i.Right.LeftLength - i.Right.RightLength);
750                 if (Math.Abs (new_diff) >= diff)
751                   break;
752                 i = i.promote_right ();
753                 i.Left.balance ();
754               }
755           }
756         return i;
757       }
758
759       public MInterval Copy (int start, int end)
760       {
761         MInterval copy, left_copy = null, right_copy = null;
762
763         update_from_to ();
764
765         if (start < From)
766           {
767             if (end <= From)
768               return Left.Copy (start, end);
769             left_copy = Left.Copy (start, From);
770           }
771         if (end > To)
772           {
773             if (start >= To)
774               return Right.Copy (start, end);
775             right_copy = Right.Copy (To, end);
776           }
777
778         copy = new MInterval (Key, null, end - start, Stack);
779         remove_properties (MTextProperty.Flag.Sensitive);
780         if (left_copy != null)
781           {
782             copy.Left = left_copy;
783             left_copy.Parent = copy;
784           }
785         if (right_copy != null)
786           {
787             copy.Right = right_copy;
788             right_copy.Parent = copy;
789           }
790         return copy;
791       }
792
793       //  this-.   ==>   this-.
794       //     right          newright-.
795       //                            right
796       private MInterval divide_right (int pos)
797       {
798         MInterval interval = new MInterval (Key, mtext, To - pos, Stack);
799
800         M17N.DebugPrint ("divide-right({0}) at ", pos); DumpOne (false, true);
801         To = pos;
802         if (Right != null)
803           {
804             interval.Right = Right;
805             Right.Parent = interval;
806             interval.Length += Right.Length;
807           }
808         interval.Parent = this;
809         Right = interval;
810         return interval;
811       }
812
813       //    .-this   ==>       .-this
814       //  left             .-newleft
815       //                 left
816       private MInterval divide_left (int pos)
817       {
818         MInterval interval = new MInterval (Key, mtext, pos - From, Stack);
819
820         M17N.DebugPrint ("divide-left({0}) at ", pos); DumpOne (false, true);
821         From = pos;
822         if (Left != null)
823           {
824             interval.Left = Left;
825             Left.Parent = interval;
826             interval.Length += Left.Length;
827           }
828         interval.Parent = this;
829         Left = interval;
830         return interval;
831       }
832
833       private void remove_properties (MTextProperty.Flag flags)
834       {
835         for (MPlist p = Stack; ! p.IsEmpty;)
836           {
837             MTextProperty prop = (MTextProperty) p.Val;
838
839             if ((prop.flags & flags) == flags)
840               p.Pop ();
841             else
842               p = p.Next;
843           }
844       }
845
846       private void inherit_front_properties (MPlist plist)
847       {
848         for (MInterval i = LeftMost; i != null; i = i.Next)
849           {
850             if (! Stack.IsEmpty)
851               break;
852             for (MPlist p = plist; ! p.IsEmpty; p = p.Next)
853               {
854                 MTextProperty prop = (MTextProperty) p.Val;
855
856                 if ((prop.flags & MTextProperty.Flag.RearSticky)
857                     == MTextProperty.Flag.RearSticky)
858                   i.Stack.Add (prop.key, prop);
859               }
860           }
861       }
862
863       private void inherit_rear_properties (MPlist plist)
864       {
865         for (MInterval i = RightMost; i != null; i = i.Prev)
866           {
867             if (! Stack.IsEmpty)
868               break;
869             for (MPlist p = plist; ! p.IsEmpty; p = p.Next)
870               {
871                 MTextProperty prop = (MTextProperty) p.Val;
872
873                 if ((prop.flags & MTextProperty.Flag.FrontSticky)
874                     == MTextProperty.Flag.FrontSticky)
875                   i.Stack.Add (prop.key, prop);
876               }
877           }
878       }
879
880       private MInterval delete_node_forward ()
881       {
882         if (Parent != null)
883           {
884             int len = Length - RightLength;
885
886             for (MInterval i = Parent; i != null; i = i.Parent)
887               i.Length -= len;
888             if (Parent.Left == this)
889               Parent.Left = Right;
890             else
891               Parent.Right = Right;
892           }
893
894         if (Right != null)
895           {
896             Right.Parent = Parent;
897             return Right.LeftMost;
898           }
899         return Parent;
900       }
901
902       private MInterval delete_node_backward ()
903       {
904         if (Parent != null)
905           {
906             int len = Length - RightLength;
907
908             for (MInterval i = Parent; i != null; i = i.Parent)
909               i.Length -= len;
910             if (Parent.Left == this)
911               Parent.Left = Left;
912             else
913               Parent.Right = Left;
914           }
915
916         if (Left != null)
917           {
918             Left.Parent = Parent;
919             return Left.RightMost;
920           }
921         return Parent;
922       }
923
924       private void set_mtext (MText mt)
925       {
926         mtext = mt;
927         if (Left != null)
928           Left.set_mtext (mt);
929         if (Right != null)
930           Right.set_mtext (mt);
931       }
932
933       private MInterval graft (MInterval interval, bool forward, out int len)
934       {
935         MInterval i;
936
937         len = 0;
938         if (forward)
939           {
940             i = interval.LeftMost;
941             while (i != null)
942               {
943                 if (! mergeable (i))
944                   break;
945                 len += i.Length - i.RightLength;
946                 i = i.delete_node_forward ();
947               }
948           }
949         else
950           {
951             i = interval.RightMost;
952             while (i != null)
953               {
954                 if (! mergeable (i))
955                   break;
956                 len += i.Length - i.LeftLength;
957                 i = i.delete_node_backward ();
958               }
959           }
960
961         Length += len;
962         To += len;
963         for (MInterval prev = this, ii = this.Parent; ii != null;
964              prev = ii, ii = ii.Parent)
965           {
966             ii.Length += len;
967             if (prev == ii.Left)
968               {
969                 ii.From += len;
970                 ii.To += len;;
971               }
972           }
973         if (i != null)
974           while (i.Parent != null) i = i.Parent;
975         return i;
976       }
977
978       public void Insert (int pos, MInterval interval)
979       {
980         update_from_to ();
981         M17N.DebugPrint ("insert({0}) at {1} in ", interval.Length, pos);
982         DumpOne (false, true);
983
984         interval.set_mtext (mtext);
985
986         if (pos < From)
987           Prev.Insert (pos, interval);
988         else if (pos == From)
989           {
990             MInterval prev = Prev;
991
992             if (prev != null)
993               {
994                 if (Left == null)
995                   {
996                     prev.Insert (pos, interval);
997                     return;
998                   }
999                 prev.remove_properties
1000                   (MTextProperty.Flag.Sensitive|MTextProperty.Flag.RearSticky);
1001                 interval.inherit_front_properties (prev.Stack);
1002               }
1003             remove_properties
1004               (MTextProperty.Flag.Sensitive|MTextProperty.Flag.FrontSticky);
1005             interval.inherit_rear_properties (Stack);
1006
1007             int len;
1008             interval = graft (interval, false, out len);
1009             if (interval != null && prev != null)
1010               interval = prev.graft (interval, true, out len);
1011             if (interval != null)
1012               {
1013                 MInterval i;
1014
1015                 if (Left != null)
1016                   {
1017                     //    .-this-.   ==>          .-this-.
1018                     // left-.                 .-left-.
1019                     //    child                     child-.
1020                     //                                 interval
1021                     i = Left.RightMost;
1022                     i.Right = interval;
1023                   }
1024                 else
1025                   {
1026                     Left = interval;
1027                     i = this;
1028                   }
1029                 interval.Parent = i;
1030                 for (; i != null; i = i.Parent)
1031                   i.Length += interval.Length;
1032               }
1033           }
1034         else if (pos < To)
1035           {
1036             remove_properties (MTextProperty.Flag.Sensitive);
1037
1038             int len;
1039             interval = graft (interval, true, out len);
1040             pos += len;
1041             if (interval != null)
1042               interval = graft (interval, false, out len);
1043             if (interval != null)
1044               {
1045                 divide_right (pos);
1046                 Right.Left = interval;
1047                 interval.Parent = Right;
1048                 for (MInterval i = Right; i != null; i = i.Parent)
1049                   i.Length += interval.Length;
1050               }
1051           }
1052         else if (pos == To)
1053           {
1054             MInterval next = Next;
1055
1056             if (next != null)
1057               {
1058                 if (Right == null)
1059                   {
1060                     next.Insert (pos, interval);
1061                     return;
1062                   }
1063                 next.remove_properties
1064                   (MTextProperty.Flag.Sensitive|MTextProperty.Flag.FrontSticky);
1065                 interval.inherit_rear_properties (next.Stack);
1066               }
1067             remove_properties
1068               (MTextProperty.Flag.Sensitive|MTextProperty.Flag.RearSticky);
1069             interval.inherit_front_properties (Stack);
1070
1071             int len;
1072             interval = graft (interval, true, out len);
1073             if (interval != null && next != null)
1074               interval = next.graft (interval, false, out len);
1075             if (interval != null)
1076               {
1077                 MInterval i;
1078
1079                 if (Right != null)
1080                   {
1081                     //    .-this-.   ==>          .-this-.
1082                     //         .-right                 .-right
1083                     //     child                  .-child
1084                     //                        interval
1085
1086                     i = Right.LeftMost;
1087                     i.Left = interval;
1088                   }
1089                 else
1090                   {
1091                     Right = interval;
1092                     i = this;
1093                   }
1094                 interval.Parent = i;
1095                 for (; i != null; i = i.Parent)
1096                   i.Length += interval.Length;
1097               }
1098           }
1099         else                    // (pos > To)
1100           Next.Insert (pos, interval);
1101       }
1102
1103       private void vacate_node (MInterval interval)
1104       {
1105         vacate_node (interval, null);
1106       }
1107
1108       private void vacate_node (MInterval interval, MInterval stop)
1109       {
1110         if (interval != null)
1111           M17N.DebugPrint ("vacate #{0} to #{1}\n", ID, interval.ID);
1112         else
1113           M17N.DebugPrint ("vacate #{0} to null\n", ID);
1114         if (interval != null)
1115           interval.Parent = Parent;
1116         if (Parent == null)
1117           {
1118             if (mtext != null)
1119               mtext.intervals.Put (Key, interval);
1120           }
1121         else
1122           {
1123             if (this == Parent.Right)
1124               Parent.Right = interval;
1125             else
1126               Parent.Left = interval;
1127
1128             int diff = Length;
1129             if (interval != null)
1130               diff -= interval.Length;
1131             for (MInterval i = Parent; i != stop; i = i.Parent)
1132               i.Length -= diff;
1133           }
1134       }
1135
1136       public void Delete (int start, int end)
1137       {
1138         update_from_to ();
1139         M17N.DebugPrint ("delete({0} {1}) from ", start, end); DumpOne (false, true);
1140         if (start < From)
1141           {
1142             if (end <= From)
1143               {
1144                 Left.Delete (start, end);
1145                 return;
1146               }
1147             Left.Delete (start, From);
1148             To -= From - start;
1149             end -= From - start;
1150             From = start;
1151           }
1152         if (end > To)
1153           {
1154             if (start >= To)
1155               {
1156                 Right.Delete (start, end);
1157                 return;
1158               }
1159             Right.Delete (To, end);
1160             end = To;
1161           }
1162         if (start == From && end == To)
1163           {
1164             if (Right == null)
1165               {
1166                 vacate_node (Left);
1167               }
1168             else
1169               {
1170                 if (Left != null)
1171                   {
1172                     MInterval i;
1173                 
1174                     for (i = Right; i.Left != null; i = i.Left)
1175                       i.Length += Left.Length;
1176                     i.Length += Left.Length;
1177                     i.Left = Left;
1178                     Left.Parent = i;
1179                   }
1180                 vacate_node (Right);
1181               }
1182           }
1183         else
1184           {
1185             int len = end - start;
1186
1187             for (MInterval i = this; i != null; i = i.Parent)
1188               i.Length -= len;
1189           }
1190       }
1191
1192       public void Push (int start, int end, MTextProperty prop)
1193       {
1194         update_from_to ();
1195         M17N.DebugPrint ("push({0} {1}) at ", start, end); DumpOne (false, true);
1196         if (start < From)
1197           {
1198             if (end <= From)
1199               {
1200                 Left.Push (start, end, prop);
1201                 return;
1202               }
1203             Left.Push (start, From, prop);
1204             start = From;
1205           }
1206         if (end > To)
1207           {
1208             if (start >= To)
1209               {
1210                 Right.Push (start, end, prop);
1211                 return;
1212               }
1213             Right.Push (To, end, prop);
1214             end = To;
1215           }
1216
1217         if (start > From)
1218           divide_left (start);
1219         if (end < To)
1220           divide_right (end);
1221         Stack.Push (prop.key, prop);
1222       }
1223
1224       private static void merge_nodes (MInterval head, MInterval tail)
1225       {
1226         M17N.DebugPrint ("merging "); head.DumpOne (true, false);
1227         M17N.DebugPrint (" through "); tail.DumpOne (true, false);
1228
1229         int from = head.From;
1230         int to = tail.To;
1231         MInterval root;
1232
1233         for (root = head; root.To + head.RightLength < to;
1234              root = root.Parent);
1235         
1236         M17N.DebugPrint (" common root is "); root.DumpOne (false, true);
1237
1238         if (from < root.From)
1239           {
1240             MInterval prev = root.Prev;
1241
1242             while (true)
1243               {
1244                 M17N.DebugPrint ("merging "); prev.DumpOne (false, true);
1245                 prev.vacate_node (prev.Left, root);
1246                 if (prev == head)
1247                   break;
1248                 if (prev.Left != null)
1249                   prev = prev.Left.RightMost;
1250                 else
1251                   prev = prev.Parent;
1252               }
1253           }
1254         if (root.To < to)
1255           {
1256             MInterval next = root.Next;
1257
1258             while (true)
1259               {
1260                 M17N.DebugPrint ("merging "); next.DumpOne (false, true);
1261                 next.vacate_node (next.Right, root);
1262                 if (next == tail)
1263                   break;
1264                 if (next.Right != null)
1265                   next = next.Right.LeftMost;
1266                 else
1267                   next = next.Parent;
1268               }
1269           }
1270       }
1271
1272       public void MergeAfterChange (int start, int end)
1273       {
1274         update_from_to ();
1275         if (start < From)
1276           {
1277             Prev.MergeAfterChange (start, end);
1278             return;
1279           }
1280
1281         MInterval head = this, tail = this, i;
1282
1283         if (start == From && start > 0)
1284           {
1285             i = Prev;
1286             if (mergeable (i))
1287               head = i;
1288           }
1289         while (tail.To < end)
1290           {
1291             i = tail.Next;
1292             if (! tail.mergeable (i))
1293               {
1294                 if (head != tail)
1295                   merge_nodes (head, tail);
1296                 head = i;
1297               }
1298             tail = i;
1299           }
1300         while (true)
1301           {
1302             i = tail.Next;
1303             if (i == null || ! tail.mergeable (i))
1304               break;
1305             tail = i;
1306           }
1307         if (head != tail)
1308           merge_nodes (head, tail);
1309       }
1310
1311       public void Pop (int start, int end)
1312       {
1313         update_from_to ();
1314         M17N.DebugPrint ("pop({0} {1}) at ", start, end); DumpOne (false, true);
1315         if (start < From)
1316           {
1317             if (end <= From)
1318               {
1319                 Left.Pop (start, end);
1320                 return;
1321               }
1322             Left.Pop (start, From);
1323             start = From;
1324           }
1325         if (end > To)
1326           {
1327             if (start >= To)
1328               {
1329                 Right.Pop (start, end);
1330                 return;
1331               }
1332             Right.Pop (To, end);
1333             end = To;
1334           }
1335
1336         if (! Stack.IsEmpty)
1337           {
1338             if (start > From)
1339               divide_left (start);
1340             if (end < To)
1341               divide_right (end);
1342             Stack.Pop ();
1343           }
1344       }
1345
1346       private void DumpOne (bool with_prop, bool newline)
1347       {
1348         DumpOne (with_prop, newline, false);
1349       }
1350
1351       private void DumpOne (bool with_prop, bool newline, bool force)
1352       {
1353         if (force || M17N.debug)
1354           {
1355             Console.Write ("#{0}({1} {2} {3}", ID, Length, From, To);
1356             if (with_prop)
1357               foreach (MPlist p in Stack)
1358                 Console.Write (" " + p.Val);
1359             Console.Write (")");
1360             if (newline)
1361               Console.WriteLine ();
1362             if (Length <= 0)
1363               throw new Exception ("Invalid interval length");
1364           }
1365       }
1366
1367       public void Dump () { Dump (false); }
1368
1369       public void Dump (bool force)
1370       {
1371         if (force || M17N.debug)
1372           {
1373             update_from_to ();
1374
1375             if (Left != null)
1376               Left.Dump (force);
1377             if (From > 0)
1378               Console.Write (" ");
1379             DumpOne (true, false, force);
1380             if (Right != null)
1381               Right.Dump (force);
1382           }
1383       }
1384
1385       private int Depth {
1386         get { return (Parent == null ? 0 : Parent.Depth + 1); }
1387       }
1388
1389       public void DumpNested (bool force)
1390       {
1391         DumpNested ("", force);
1392       }
1393
1394       public void DumpNested (string indent, bool force)
1395       {
1396         if (force || M17N.debug)
1397           {
1398             int indent_type = (Parent == null ? 1
1399                                : Parent.Left == this ? 0 : 2);
1400
1401             update_from_to ();
1402             if (Left != null)
1403               {
1404                 if (indent_type <= 1)
1405                   Left.DumpNested (indent + "  ", force);
1406                 else
1407                   Left.DumpNested (indent + "| ", force);
1408               }
1409             if (indent_type == 0)
1410               Console.Write (indent + ".-");
1411             else if (indent_type == 2)
1412               Console.Write (indent + "`-");
1413             DumpOne (true, true, true);
1414             if (Right != null)
1415               {
1416                 if (indent_type >= 1)
1417                   Right.DumpNested (indent + "  ", force);
1418                 else
1419                   Right.DumpNested (indent + "| ", force);
1420               }
1421           }
1422       }
1423     }
1424
1425     private class MTextEnum : IEnumerator
1426     {
1427       private MText mt;
1428       private int pos = -1;
1429
1430       public MTextEnum (MText mt)
1431         {
1432           this.mt = mt;
1433         }
1434
1435       public bool MoveNext ()
1436       {
1437         pos++;
1438         return (pos < mt.nchars);
1439       }
1440
1441       public void Reset ()
1442       {
1443         pos = -1;
1444       }
1445
1446       public object Current
1447       {
1448         get {
1449           //if (pos < 0 || pos >= mt.nchars)
1450           //throw new InvalidOperationException ();
1451           return mt[pos];
1452         }
1453       }
1454     }
1455   }
1456 }