*** 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 MProperty
23   {
24     [FlagsAttribute]
25     public enum Flags
26     {
27       None =            0x00,
28       /// A text inserted before a character that has this property
29       /// inherits this property.  If the text already has properties
30       /// of the same key, they are deleted.
31       FrontSticky =     0x01,
32       /// A text inserted after a character that has this property
33       /// inherits this property.  If the text already has properties
34       /// of the same key, they are deleted.
35       RearSticky =      0x02,
36       /// This property is deleted from a span of text if the span is
37       /// modified (i.e. a character is changed, a text is inserted,
38       /// some part is deleted).  This propery is also deleted if a
39       /// property of the same key is added, which means that this
40       /// property is not stackable.
41       Sensitive =       0x04,
42       /// Like Sensitive but also this property is deleted from a span
43       /// of text if a text just before the span is modified,
44       /// inserted, or deleted.
45       FrontSensitive =  0x08,
46       /// Like Sensitive but also this property is deleted from a span
47       /// of text if a text just after the span is modified, inserted,
48       /// or deleted.
49       RearSensitive =   0x10
50     };
51
52     internal MSymbol key;
53     internal object val;
54
55     public MSymbol Key { get { return key; } }
56     public object Val { get { return val; } }
57
58     public MProperty (MSymbol key, object val)
59     {
60       if (key.flags == null)
61         key.flags = Flags.None;
62       this.key = key;
63       this.val = val;
64     }
65
66     public MProperty (string name, object val)
67     {
68       key = MSymbol.PropertyKey (name);
69       this.val = val;
70     }
71
72     public static bool HasFlags (MSymbol key, Flags flags)
73     {
74       return ((key.flags & flags) != Flags.None);
75     }
76
77     public override string ToString ()
78     {
79       return key.ToString () + ":" + val;
80     }
81   }
82
83   public class MText : IEnumerable, IEquatable<MText>, IComparable<MText>
84   {
85 #if false
86     public enum MTextFormat format;
87 #endif
88     private StringBuilder sb;
89     private int nchars;
90     private int cache_pos;
91     private int cache_idx;
92     private MPlist intervals;
93     private MPlist default_property;
94     private bool read_only;
95
96     private static UTF8Encoding utf8 = new UTF8Encoding ();
97
98     private static int count_chars (String str)
99     {
100       int len = str.Length, n = 0;
101
102       for (int i = 0; i < len; i++, n++) 
103         if (surrogate_high_p (str[i]))
104           i++;
105       return n;
106     }
107
108     private static int count_chars (StringBuilder str)
109     {
110       int len = str.Length, n = 0;
111
112       for (int i = 0; i < len; i++, n++) 
113         if (surrogate_high_p (str[i]))
114           i++;
115       return n;
116     }
117
118     public MText ()
119       {
120         sb = new StringBuilder ();
121         intervals = new MPlist ();
122       }
123
124     public MText (byte[] str)
125       {
126         sb = new StringBuilder (utf8.GetString (str));
127         nchars = count_chars (sb);
128         intervals = new MPlist ();
129       }
130
131     public MText (String str)
132       {
133         sb = new StringBuilder (str);
134         nchars = count_chars (str);
135         intervals = new MPlist ();
136       }
137
138     public MText (StringBuilder str)
139       {
140         sb = str;
141         nchars = count_chars (str);
142         intervals = new MPlist ();
143       }
144
145     public static MText operator+ (object obj, MText mt)
146     {
147       if (obj is string)
148         {
149           MText mtnew = new MText ((string) obj);
150           return mtnew.Ins (mtnew.Length, mt);
151         }
152       throw new Exception ("Unknown object type: " + obj.GetType());
153     }
154
155     public static MText operator+ (MText mt, object obj)
156     {
157       if (obj is string)
158         return mt + new MText ((string) obj);
159       if (obj is int)
160         return mt.Dup ().Ins (mt.Length, (int) obj);
161       if (obj is char)
162         return mt.Dup ().Ins (mt.Length, (int) ((char) obj));
163       throw new Exception ("Unknown object type: " + obj.GetType());
164     }
165
166     public static MText operator+ (MText mt1, MText mt2)
167     {
168       return mt1.Dup ().Ins (mt1.Length, mt2);
169     }
170
171     // Public properties
172     public bool ReadOnly { get { return read_only; } }
173     public int Length { get { return nchars; } }
174
175     // Public methods
176
177     // for IEnumerable interface
178     public IEnumerator GetEnumerator() { return new MTextEnum (this); }
179
180     // for IEquatable interface
181     public bool Equals (MText other) { return this.sb.Equals (other.sb); }
182
183     // for IComparable interface
184     public int CompareTo (MText other)
185     {
186       return this.sb.ToString ().CompareTo (other.sb.ToString ());
187     }
188
189     public override string ToString () { return sb.ToString (); }
190
191     private static bool surrogate_high_p (char c)
192     {
193       return (c >= 0xD800 && c < 0xDC00);
194     }
195
196     private static bool surrogate_low_p (char c)
197     {
198       return (c >= 0xDC00 && c < 0xE000);
199     }
200
201     private static int inc_idx (StringBuilder sb, int i)
202     {
203       return (i + (surrogate_high_p (sb[i]) ? 2 : 1));
204     }
205
206     private static int dec_idx (StringBuilder sb, int i)
207     {
208       return (i - (surrogate_low_p (sb[i - 1]) ? 2 : 1));
209     }
210
211     private static int pos_to_idx (MText mt, int pos)
212     {
213       if (pos == mt.cache_pos)
214         return mt.cache_idx;
215
216       int p, i;
217       bool forward;
218
219       if (pos < mt.cache_pos)
220         {
221           if (mt.cache_pos == mt.cache_idx)
222             return mt.cache_idx;
223           if (pos < mt.cache_pos - pos)
224             {
225               p = i = 0;
226               forward = true;
227             }
228           else
229             {
230               p = mt.cache_pos; i = mt.cache_idx;
231               forward = false;
232             }
233         }
234       else
235         {
236           if (mt.nchars - mt.cache_pos == mt.sb.Length - mt.cache_idx)
237             return (mt.cache_idx + pos - mt.cache_pos);
238           if (pos - mt.cache_pos < mt.nchars - pos)
239             {
240               p = mt.cache_pos; i = mt.cache_idx;
241               forward = true;
242             }
243           else
244             {
245               p = mt.nchars; i = mt.sb.Length;
246               forward = false;
247             }
248         }
249       if (forward)
250         for (; p < pos; i = inc_idx (mt.sb, i), p++);
251       else
252         for (; p > pos; i = dec_idx (mt.sb, i), p--);
253       mt.cache_pos = p;
254       mt.cache_idx = i;
255       return i;
256     }
257
258     private void check_pos (int pos, bool tail_ok)
259     {
260       if (pos < 0 || (tail_ok ? pos > nchars : pos >= nchars))
261         throw new Exception ("Invalid MText position:" + pos);
262     }
263
264     private bool check_range (int from, int to, bool zero_ok)
265     {
266       if (from < 0 || (zero_ok ? from > to : from >= to)
267           || to > nchars)
268         throw new Exception ("Invalid MText range");
269       return (from == to);
270     }
271
272     private void insert (int pos, MText mt2, int from, int to)
273     {
274       check_pos (pos, true);
275
276       if (M17n.debug)
277         {
278           Console.Write ("inserting {0} to {1} of ", from, to);
279           mt2.DumpPropNested ();
280         }
281       if (from == to)
282         return;
283       foreach (MPlist plist in intervals)
284         {
285           MInterval root = (MInterval) plist.Val;
286           MPlist p = mt2.intervals.Find (plist.Key);
287           MInterval i = p == null ? null : (MInterval) p.Val;
288
289           root.Insert (pos, i, from, to);
290         }
291       foreach (MPlist plist in mt2.intervals)
292         if (intervals.Find (plist.Key) == null)
293           {
294             MInterval root;
295
296             if (nchars == 0)
297               root = ((MInterval) plist.Val).Copy (this, from, to);
298             else
299               {
300                 root = new MInterval (plist.Key, this);
301                 root.Insert (pos, (MInterval) plist.Val, from, to);
302               }
303             intervals.Push (plist.Key, root);
304           }
305
306       int pos_idx = pos_to_idx (this, pos);
307       int from_idx = pos_to_idx (mt2, from);
308       int to_idx = pos_to_idx (mt2, to);
309
310       sb.Insert (pos_idx, mt2.sb.ToString (from_idx, to_idx - from_idx));
311       nchars += to - from;
312     }
313
314     private void insert (int pos, int c)
315     {
316       check_pos (pos, true);
317
318       int pos_idx = pos_to_idx (this, pos);
319
320       if (c < 0x10000)
321         {
322           char ch = (char) c;
323           sb.Insert (pos_idx, ch);
324         }
325       else
326         {
327           char high = (char) (0xD800 + ((c - 0x10000) >> 10));
328           char low = (char) (0xDC00 + ((c - 0x10000) & 0x3FF));
329           sb.Insert (pos_idx, low);
330           sb.Insert (pos_idx, high);
331         }
332       nchars++;
333       foreach (MPlist plist in intervals)
334         ((MInterval) plist.Val).Insert (pos, null, 0, 1);
335     }
336
337     public int this[int i]
338     {
339       set {
340         i = pos_to_idx (this, i);
341         if (value < 0x10000)
342           {
343             if (surrogate_high_p (sb[i]))
344               sb.Remove (i, 1);
345             sb[i] = (char) value;
346           }
347         else
348           {
349             char high = (char) (0xD800 + ((value - 0x10000) >> 10));
350             char low = (char) (0xDC00 + ((value - 0x10000) & 0x3FF));
351
352             if (! surrogate_high_p (sb[i]))
353               sb.Insert (i, 0);
354             sb[i] = high;
355             sb[i + 1] = low;
356           }
357       }
358       get {
359         i = pos_to_idx (this, i);
360         return (surrogate_high_p (sb[i])
361                 ? ((sb[i] - 0xD800) << 10) + (sb[i + 1] - 0xDC00) + 0x10000
362                 : sb[i]);
363       }
364     }
365
366     public MText Dup ()
367     {
368       MText mt = new MText (sb.ToString ());
369
370       foreach (MPlist p in intervals)
371         mt.intervals.Add (p.Key, ((MInterval) p.Val).Copy (mt, 0, Length));
372       return mt;
373     }
374
375     public MText Dup (int from, int to)
376     {
377       if (check_range (from, to, true))
378         return new MText ();
379       int from_idx = pos_to_idx (this, from);
380       int len = pos_to_idx (this, to) - from_idx;
381       MText mt = new MText (sb.ToString ().Substring (from_idx, len));
382
383       foreach (MPlist p in intervals)
384         mt.intervals.Add (p.Key, ((MInterval) p.Val).Copy (mt, from, to));
385       return mt;
386     }
387
388     public MText Ins (int pos, int c)
389     {
390       insert (pos, c);
391       return this;
392     }
393
394     public MText Ins (int pos, MText mt)
395     {
396       insert (pos, mt, 0, mt.nchars);
397       return this;
398     }
399
400     public MText Ins (int pos, MText mt, int from, int to)
401     {
402       insert (pos, mt, from, to);
403       return this;
404     }
405
406     public MText Cat (int c)
407     {
408       insert (nchars, c);
409       return this;
410     }
411
412     public MText Del (int from, int to)
413     {
414       if (check_range (from, to, true))
415         return this;
416
417       sb.Remove (from, pos_to_idx (this, to) - pos_to_idx (this, from));
418       nchars -= to - from;
419
420       if (nchars > 0)
421         foreach (MPlist plist in intervals)
422           {
423             MInterval root = (MInterval) plist.Val;
424             root.Delete (from, to);
425             if (from > 0 && from < nchars)
426               ((MInterval) plist.Val).MergeAfterChange (from, from);
427           }
428       else
429         intervals.Clear ();
430       if (M17n.debug)
431         DumpPropNested ();
432       return this;
433     }
434
435     public object GetProp (int pos, MSymbol key)
436     {
437       check_pos (pos, false);
438
439       MInterval i = (MInterval) intervals.Get (key);
440       if (i == null)
441         return null;
442
443       MProperty prop = i.Get (pos);
444       return (prop != null ? prop.Val : null);
445     }
446
447     public object GetProp (int pos, MSymbol key, out MProperty prop)
448     {
449       check_pos (pos, false);
450
451       MInterval i = (MInterval) intervals.Get (key);
452       if (i == null)
453         return (prop = null);
454       prop = i.Get (pos);
455       return (prop != null ? prop.Val : null);
456     }
457
458     public object GetProp (int pos, MSymbol key, out MProperty[] array)
459     {
460       check_pos (pos, false);
461
462       MInterval i = (MInterval) intervals.Get (key);
463       if (i == null)
464         return (array = null);
465       MProperty prop = i.Get (pos, out array);
466       return (prop != null ? prop.Val : null);
467     }
468
469     public void PushProp (int from, int to, MSymbol key, object val)
470     {
471       if (! check_range (from, to, true))
472         PushProp (from, to, new MProperty (key, val));
473     }
474
475     public void PushProp (int from, int to, MProperty prop)
476     {
477       if (from < 0)
478         {
479           if (default_property == null)
480             default_property = new MPlist ();
481           default_property.Push (prop.key, prop.val);
482         }
483       else
484         {
485           if (check_range (from, to, true))
486             return;
487
488           MPlist p = intervals.Find (prop.key);
489           MInterval root;
490
491           if (p == null)
492             {
493               root = new MInterval (prop.key, this);
494               intervals.Push (prop.key, root);
495             }
496           else
497             root = (MInterval) p.Val;
498
499           if (root.isSensitive)
500             root.PopSensitive (from, to);
501           root.Push (from, to, prop);
502           root.MergeAfterChange (from, to);
503           root.Balance ();
504         }
505     }
506
507     public void PopProp (int from, int to, MSymbol key)
508     {
509       if (from < 0)
510         {
511           if (default_property == null)
512             return;
513           MPlist p = default_property.Find (key);
514
515           if (p != null)
516             p.Pop ();
517         }
518       else
519         {
520           if (check_range (from, to, true))
521             return;
522
523           MPlist p = intervals.Find (key);
524
525           if (p != null)
526             {
527               MInterval root = (MInterval) p.Val;
528               if (root.isSensitive)
529                 root.PopSensitive (from, to);
530               else
531                 root.Pop (from, to);
532               root = (MInterval) p.Val;
533               if (M17n.debug)
534                 DumpPropNested ();
535               root.MergeAfterChange (from, to);
536               root.Balance ();
537             }
538         }
539     }
540
541     public void DumpProp ()
542     {
543       Console.Write ("(");
544       foreach (MPlist p in intervals)
545         ((MInterval) p.Val).Dump (true);
546       Console.WriteLine (")");
547     }
548
549     public void DumpPropNested ()
550     {
551       Console.WriteLine ("total length = {0}", Length);
552       foreach (MPlist p in intervals)
553         ((MInterval) p.Val).DumpNested (true);
554     }
555
556     private class MInterval
557     {
558       // position: 0   1   2   3   4   5   6   7
559       //           | A | B | C | D | E   F | G |
560       // interval  |---|---|---|<->|-------|---|
561       //           |---|<->|---|   |<----->|---|
562       //           |<->|   |<->|           |<->|
563       // 
564       //                      [7 (3 4)]
565       //              [3 (1 2)]       [3 (4 6)]
566       //         [1 (0 1)] [2 (2 3)]      [1 (6 7)]
567       //
568       private static int count = 0;
569       private int ID;
570       private int Length;
571       private int From, To;
572       private MSymbol Key;
573       private MPlist Stack;
574       private MInterval Left, Right, Parent;
575       private MText mtext;
576
577       public MInterval (MSymbol key, MText mt, int length)
578       {
579         if (length <= 0)
580           throw new Exception ("Invalid interval length");
581         Key = key;
582         mtext = mt;
583         Length = length;
584         Stack = new MPlist ();
585         ID = count++;
586       }
587
588       public MInterval (MSymbol key, MText mt)
589       {
590         Key = key;
591         mtext = mt;
592         Length = mt.sb.Length;
593         From = 0;
594         To = Length;
595         Stack = new MPlist ();
596         ID = count++;
597       }
598
599       /// POS must be smaller than Length;
600       public MProperty Get (int pos)
601       {
602         MInterval i = find_head (pos);
603
604         return (i.Stack.IsEmpty ? null : (MProperty) i.Stack.Val);
605       }
606
607       /// POS must be smaller than Length;
608       public MProperty Get (int pos, out MProperty[] array)
609       {
610         MInterval i = find_head (pos);
611
612         if (i.To == pos)
613           i = i.Next;
614         if (i.Stack.IsEmpty)
615           {
616             array = null;
617             return null;
618           }
619         array = new MProperty[i.Stack.Count];
620
621         int idx;
622         MPlist p;
623         for (idx = 0, p = i.Stack; ! p.IsEmpty; idx++, p = p.Next)
624           array[idx] = (MProperty) p.Val;
625         return array[0];
626       }
627
628       private MInterval (MSymbol key, MText mt, int length, MPlist stack)
629       {
630         Key = key;
631         mtext = mt;
632         Length = length;
633         From = 0;
634         To = Length;
635         Stack = stack == null ? new MPlist () : stack.Clone ();
636         ID = count++;
637       }
638
639       private bool isRearSticky
640       {
641         get { return MProperty.HasFlags (Key, MProperty.Flags.RearSticky) ; }
642       }
643
644       private bool isFrontSticky
645       {
646         get { return MProperty.HasFlags (Key, MProperty.Flags.FrontSticky) ; }
647       }
648
649       public bool isSensitive
650       {
651         get { return MProperty.HasFlags (Key, MProperty.Flags.Sensitive) ; }
652       }
653
654       public bool isFrontSensitive
655       {
656         get { return MProperty.HasFlags (Key,
657                                          MProperty.Flags.FrontSensitive) ; }
658       }
659
660       public bool isRearSensitive
661       {
662         get { return MProperty.HasFlags (Key,
663                                          MProperty.Flags.RearSensitive) ; }
664       }
665
666       public bool isAnySensitive
667       {
668         get { return MProperty.HasFlags (Key,
669                                          (MProperty.Flags.Sensitive
670                                           | MProperty.Flags.RearSensitive
671                                           | MProperty.Flags.FrontSensitive)) ; }
672       }
673
674       private void update_from_to ()
675       {
676         if (Parent == null)
677           {
678             From = LeftLength;
679             To = Length - RightLength;
680           }
681         else if (Parent.Left == this)
682           {
683             From = Parent.From - Length + LeftLength;
684             To = Parent.From - RightLength;
685           }
686         else
687           {
688             From = Parent.To + LeftLength;
689             To = Parent.To + Length - RightLength;
690           }
691       }
692
693       private int LeftLength
694       {
695         get { return (Left == null ? 0 : Left.Length); }
696       }
697
698       private int RightLength
699       {
700         get { return (Right == null ? 0 : Right.Length); }
701       }
702
703       private MInterval LeftMost
704       {
705         get {
706           update_from_to ();
707           if (Left == null)
708             return this;
709           return Left.LeftMost;
710         }
711       }
712
713       private MInterval RightMost
714       {
715         get {
716           update_from_to ();
717           if (Right == null)
718             return this;
719           return Right.RightMost;
720         }
721       }
722
723       private MInterval Prev {
724         get {
725           MInterval i;
726
727           if (Left != null)
728             {
729               for (i = Left; i.Right != null; i = i.Right)
730                 i.update_from_to ();
731               i.update_from_to ();
732             }
733           else
734             {
735               MInterval child = this;
736               for (i = Parent; i != null && i.Left == child;
737                    child = i, i = i.Parent);
738             }
739           return i;
740         }
741       }
742
743       private MInterval Next {
744         get {
745           MInterval i;
746
747           if (Right != null)
748             {
749               for (i = Right; i.Left != null; i = i.Left)
750                 i.update_from_to ();
751               i.update_from_to ();
752             }
753           else
754             {
755               MInterval child = this;
756               for (i = Parent; i != null && i.Right == child;
757                    child = i, i = i.Parent);
758             }
759           return i;
760         }
761       }
762
763       private MInterval find_head (int pos)
764       {
765         update_from_to ();
766         if (pos < From)
767           return Left.find_head (pos);
768         if (pos >= To)
769           return Right.find_head (pos);
770         return this;
771       }
772
773       private MInterval find_tail (int pos)
774       {
775         update_from_to ();
776         if (pos <= From)
777           return Left.find_tail (pos);
778         if (pos > To)
779           return Right.find_tail (pos);
780         return this;
781       }
782
783       private bool mergeable (MInterval i)
784       {
785         MPlist p1, p2;
786
787         for (p1 = Stack, p2 = i.Stack; ! p1.IsEmpty && ! p2.IsEmpty;
788              p1 = p1.Next, p2 = p2.Next)
789           if (p1.Val != p2.Val)
790             return false;
791         return (p1.IsEmpty && p2.IsEmpty);
792       }
793
794       //      p-. or .-p              p-. or .-p
795       //       .-this-.                .-right-.
796       //    left   .-right-.  ->   .-this-.    c2
797       //          c1       c2    left     c1
798       private MInterval promote_right ()
799       {
800         MInterval c1 = Right.Left;
801
802         // Update Parent.
803         if (Parent == null)
804           mtext.intervals.Put (Key, Right);
805         else if (Parent.Left == this)
806           Parent.Left = Right;
807         else
808           Parent.Right = Right;
809
810         // Update Right.
811         Right.Parent = Parent;
812         Right.Left = this;
813         Right.Length += LeftLength + (To - From);
814
815         // Update this.
816         Parent = Right;
817         Right = c1;
818         Length = LeftLength + (To - From) + RightLength;
819
820         // Update C1 if necessary.
821         if (c1 != null)
822           c1.Parent = this;
823
824         Parent.update_from_to ();
825         return Parent;
826       }
827
828       //      p-. or .-p              p-. or .-p
829       //       .-this-.                .-left-.
830       //  .-left-.  .-right-.  ->     c1    .-this-.
831       // c1      c2                        c2     right
832       private MInterval promote_left ()
833       {
834         MInterval c2 = Left.Right;
835
836         // Update Parent.
837         if (Parent == null)
838           mtext.intervals.Put (Key, Left);
839         else if (Parent.Left == this)
840           Parent.Left = Left;
841         else
842           Parent.Right = Left;
843
844         // Update Left.
845         Left.Parent = Parent;
846         Left.Right = this;
847         Left.Length += (To - From) + RightLength;
848
849         // Update this.
850         Parent = Left;
851         Left = c2;
852         Length = LeftLength + (To - From) + RightLength;
853
854         // Update C2 if necessary.
855         if (c2 != null)
856           c2.Parent = this;
857
858         Parent.update_from_to ();
859         return Parent;
860       }
861
862       public MInterval Balance ()
863       {
864         MInterval i = this;
865
866         update_from_to ();
867         while (true)
868           {
869             //       .-this-.
870             //  .-left-.  .-right-.
871             // c1     c2  c3      c4
872             int diff = i.LeftLength - i.RightLength;
873             int new_diff;
874
875             if (diff > 0)
876               {
877                 new_diff = (i.Length - i.LeftLength
878                             + i.Left.RightLength - i.Left.LeftLength);
879                 if (Math.Abs (new_diff) >= diff)
880                   break;
881                 M17n.DebugPrint ("balancing #{0} by promoting left...", i.ID);
882                 i = i.promote_left ();
883                 M17n.DebugPrint ("done\n");
884                 i.Right.Balance ();
885               }
886             else if (diff < 0)
887               {
888                 new_diff = (i.Length - i.RightLength
889                             + i.Right.LeftLength - i.Right.RightLength);
890                 if (Math.Abs (new_diff) >= diff)
891                   break;
892                 M17n.DebugPrint ("balancing #{0} by promoting right\n", i.ID);
893                 i = i.promote_right ();
894                 i.Left.Balance ();
895               }
896             else
897               break;
898           }
899         return i;
900       }
901
902       public MInterval Copy (MText mt, int start, int end)
903       {
904         MInterval copy, left_copy = null, right_copy = null;
905
906         update_from_to ();
907
908         if (start < From)
909           {
910             if (end <= From)
911               return Left.Copy (mt, start, end);
912             left_copy = Left.Copy (mt, start, From);
913           }
914         if (end > To)
915           {
916             if (start >= To)
917               return Right.Copy (mt, start, end);
918             right_copy = Right.Copy (mt, To, end);
919           }
920
921         copy = new MInterval (Key, null, end - start, Stack);
922         copy.mtext = mt;
923         if (isSensitive && (From < start || end < To))
924           copy.Stack.Clear ();
925         if (left_copy != null)
926           {
927             copy.Left = left_copy;
928             left_copy.Parent = copy;
929           }
930         if (right_copy != null)
931           {
932             copy.Right = right_copy;
933             right_copy.Parent = copy;
934           }
935         return copy;
936       }
937
938       public MInterval Copy (MText mt, int start, int end,
939                              bool first, bool last)
940       {
941         MInterval copy = Copy (mt, start, end);
942         MInterval head = find_head (start);
943         MInterval tail = find_tail (end);
944
945         if (! head.Stack.IsEmpty
946             && (isAnySensitive && head.From < start
947                 || isFrontSensitive && ! first))
948           {
949             head = copy.find_head (0);
950             head.Stack.Clear ();
951           }
952         if (! tail.Stack.IsEmpty
953             && (isAnySensitive && end < head.To
954                 || isRearSensitive && ! last))
955           {
956             tail = copy.find_tail (copy.Length);
957             tail.Stack.Clear ();
958           }
959         M17n.DebugPrint ("Copied: {0}\n", copy);
960         return copy;
961       }
962
963       //  this-.   ==>   this-.
964       //     right          newright-.
965       //                            right
966       private MInterval divide_right (int pos)
967       {
968         MInterval interval = new MInterval (Key, mtext, To - pos, Stack);
969
970         M17n.DebugPrint ("divide-right({0}) at {1}\n", pos, this);
971         To = pos;
972         if (Right != null)
973           {
974             interval.Right = Right;
975             Right.Parent = interval;
976             interval.Length += Right.Length;
977           }
978         interval.Parent = this;
979         Right = interval;
980         return interval;
981       }
982
983       //    .-this   ==>       .-this
984       //  left             .-newleft
985       //                 left
986       private MInterval divide_left (int pos)
987       {
988         MInterval interval = new MInterval (Key, mtext, pos - From, Stack);
989
990         M17n.DebugPrint ("divide-left({0}) at {1}\n", pos, this);
991         From = pos;
992         if (Left != null)
993           {
994             interval.Left = Left;
995             Left.Parent = interval;
996             interval.Length += Left.Length;
997           }
998         interval.Parent = this;
999         Left = interval;
1000         return interval;
1001       }
1002
1003       private void set_mtext (MText mt)
1004       {
1005         mtext = mt;
1006         if (Left != null)
1007           Left.set_mtext (mt);
1008         if (Right != null)
1009           Right.set_mtext (mt);
1010       }
1011
1012       private void enlarge (int len)
1013       {
1014         Length += len;
1015         To += len;
1016         for (MInterval prev = this, i = this.Parent; i != null;
1017              prev = i, i = i.Parent)
1018           {
1019             i.Length += len;
1020             if (prev == i.Left)
1021               {
1022                 i.From += len;
1023                 i.To += len;;
1024               }
1025           }
1026       }
1027
1028       private int graft_forward (MInterval interval, int start, int end)
1029       {
1030         int len;
1031
1032         if (! Stack.IsEmpty && isRearSticky)
1033           len = end - start;
1034         else if (interval == null)
1035           len = Stack.IsEmpty ? end - start : 0;
1036         else
1037           {
1038             MInterval i = interval.find_head (start);
1039
1040             len = 0;
1041             if (Stack.IsEmpty
1042                 && (isFrontSensitive
1043                     || ((isSensitive || isRearSensitive) && i.From < start)))
1044               {
1045                 M17n.DebugPrint (" grafting {0}", i);
1046                 if (i.To < end)
1047                   len = i.To - start;
1048                 else
1049                   len = end - start;
1050                 i = i.Next;
1051               }
1052             while (i != null && i.From < end && mergeable (i))
1053               {
1054                 M17n.DebugPrint (" grafting {0}", i);
1055                 len += i.To - i.From;
1056                 if (i.From < start)
1057                   len -= start - i.From;
1058                 if (i.To >= end)
1059                   {
1060                     len -= i.To - end;
1061                     break;
1062                   }
1063                 i = i.Next;
1064               }
1065           }
1066
1067         M17n.DebugPrint (" grafted {0} in {1}\n", len, this);
1068         if (len > 0)
1069           enlarge (len);
1070         return len;
1071       }
1072
1073       private int graft_backward (MInterval interval, int start, int end)
1074       {
1075         int len;
1076
1077         if (! Stack.IsEmpty && isFrontSticky)
1078           len = end - start;
1079         else if (interval == null)
1080           len = Stack.IsEmpty ? end - start : 0;
1081         else
1082           {
1083             MInterval i = interval.find_tail (end);
1084
1085             len = 0;
1086             if (Stack.IsEmpty
1087                 && (isRearSensitive
1088                     || ((isSensitive || isFrontSensitive) && end < i.To)))
1089               {
1090                 M17n.DebugPrint (" grafting {0}", i);
1091                 if (i.From <= start)
1092                   len = end - start;
1093                 else
1094                   len = end - i.From;
1095                 i = i.Prev;
1096               }
1097             while (i != null && i.To <= start && mergeable (i))
1098               {
1099                 M17n.DebugPrint (" grafting {0}", i);
1100                 len += i.To - i.From;
1101                 if (end < i.To)
1102                   len -= i.To - end;
1103                 if (i.From <= start)
1104                   {
1105                     len -= start - i.From;
1106                     break;
1107                   }
1108                 i = i.Prev;
1109               }
1110           }
1111
1112         M17n.DebugPrint (" grafted {0} in {1}\n", len, this);
1113         if (len > 0)
1114           enlarge (len);
1115         return len;
1116       }
1117
1118       public void Insert (int pos, MInterval interval, int start, int end)
1119       {
1120         update_from_to ();
1121
1122         M17n.DebugPrint ("insert({0} to {1}) at {2} in {3}",
1123                          start, end, pos, this);
1124
1125         if (pos < From)
1126           Left.Insert (pos, interval, start, end);
1127         else if (pos == From)
1128           {
1129             MInterval prev = Left != null ? Prev : null;
1130
1131             if (isFrontSensitive)
1132               Stack.Clear ();
1133             if (prev != null && isRearSensitive)
1134               prev.Stack.Clear ();
1135             if (prev != null && isRearSticky && ! prev.Stack.IsEmpty)
1136               {
1137                 prev.enlarge (end - start);
1138                 return;
1139               }
1140             if (isFrontSticky && ! Stack.IsEmpty)
1141               {
1142                 enlarge (end - start);
1143                 return;
1144               }
1145             bool front_grafted = false, rear_grafted = false;
1146             int grafted;
1147             if (prev != null
1148                 && (grafted = prev.graft_forward (interval, start, end)) > 0)
1149               {
1150                 start += grafted;
1151                 if (start == end)
1152                   return;
1153                 front_grafted = true;
1154               }
1155             if ((grafted = graft_backward (interval, start, end)) > 0)
1156               {
1157                 end -= grafted;
1158                 if (start == end)
1159                   return;
1160                 rear_grafted = true;
1161               }
1162
1163             if (interval != null)
1164               interval = interval.Copy (mtext, start, end,
1165                                         (front_grafted
1166                                          || (prev == null && start == 0)),
1167                                         rear_grafted);
1168             else
1169               interval = new MInterval (Key, mtext, end - start, null);
1170
1171             MInterval i;
1172             if (Left != null)
1173               {
1174                 //    .-this-.   ==>          .-this-.
1175                 // left-.                 .-left-.
1176                 //    child                     child-.
1177                 //                                 interval
1178                 i = Left.RightMost;
1179                 i.Right = interval;
1180               }
1181             else
1182               {
1183                 Left = interval;
1184                 i = this;
1185               }
1186             interval.Parent = i;
1187             for (; i != null; i = i.Parent)
1188               i.Length += interval.Length;
1189           }
1190         else if (pos < To)
1191           {
1192             if (! Stack.IsEmpty)
1193               {
1194                 if (isSensitive || isFrontSensitive || isRearSensitive)
1195                   Stack.Clear ();
1196                 else if (isFrontSticky || isRearSticky)
1197                   {
1198                     enlarge (end - start);
1199                     return;
1200                   }
1201               }
1202             bool front_grafted = false, rear_grafted = false;
1203             int grafted;
1204             if ((grafted = graft_forward (interval, start, end)) > 0)
1205               {
1206                 start += grafted;
1207                 if (start == end)
1208                   return;
1209                 front_grafted = true;
1210                 pos += grafted;
1211               }
1212             if ((grafted = graft_backward (interval, start, end)) > 0)
1213               {
1214                 end -= grafted;
1215                 if (start == end)
1216                   return;
1217                 rear_grafted = true;
1218               }
1219             if (interval != null)
1220               interval = interval.Copy (mtext, start, end,
1221                                         front_grafted, rear_grafted);
1222             else
1223               interval = new MInterval (Key, mtext, end - start, null);
1224
1225             divide_right (pos);
1226             Right.Left = interval;
1227             interval.Parent = Right;
1228             for (MInterval i = Right; i != null; i = i.Parent)
1229               i.Length += interval.Length;
1230           }
1231         else if (pos == To)
1232           {
1233             MInterval next = Right != null ? Next : null;
1234
1235             if (isRearSensitive)
1236               Stack.Clear ();
1237             if (next != null && isFrontSensitive)
1238               next.Stack.Clear ();
1239             if (isRearSticky && ! Stack.IsEmpty)
1240               {
1241                 enlarge (end - start);
1242                 return;
1243               }
1244             if (next != null && isFrontSticky && ! next.Stack.IsEmpty)
1245               {
1246                 next.enlarge (end - start);
1247                 return;
1248               }
1249             bool front_grafted = false, rear_grafted = false;
1250             int grafted;
1251             if (next != null
1252                 && (grafted = next.graft_backward (interval, start, end)) > 0)
1253               {
1254                 end -= grafted;
1255                 if (start == end)
1256                   return;
1257                 rear_grafted = true;
1258               }
1259             if ((grafted = graft_forward (interval, start, end)) > 0)
1260               {
1261                 start += grafted;
1262                 if (start == end)
1263                   return;
1264                 front_grafted = true;
1265               }
1266             if (interval != null)
1267               interval = interval.Copy (mtext, start, end,
1268                                         front_grafted,
1269                                         (rear_grafted
1270                                          || (next == null && end < interval.mtext.Length)));
1271             else
1272               interval = new MInterval (Key, mtext, end - start, null);
1273
1274             MInterval i;
1275             if (Right != null)
1276               {
1277                 //    .-this-.   ==>          .-this-.
1278                 //         .-right                 .-right
1279                 //     child                  .-child
1280                 //                        interval
1281
1282                 i = Right.LeftMost;
1283                 i.Left = interval;
1284               }
1285             else
1286               {
1287                 Right = interval;
1288                 i = this;
1289               }
1290             interval.Parent = i;
1291             for (; i != null; i = i.Parent)
1292               i.Length += interval.Length;
1293           }
1294         else                    // (pos > To)
1295           Right.Insert (pos, interval, start, end);
1296         M17n.DebugPrint (" done\n");
1297       }
1298
1299       private void vacate_node (MInterval interval)
1300       {
1301         vacate_node (interval, null);
1302       }
1303
1304       private void vacate_node (MInterval interval, MInterval stop)
1305       {
1306         if (interval != null)
1307           M17n.DebugPrint ("vacate #{0} to #{1}\n", ID, interval.ID);
1308         else
1309           M17n.DebugPrint ("vacate #{0} to null\n", ID);
1310         if (interval != null)
1311           interval.Parent = Parent;
1312         if (Parent == null)
1313           {
1314             if (mtext != null)
1315               mtext.intervals.Put (Key, interval);
1316           }
1317         else
1318           {
1319             if (this == Parent.Right)
1320               Parent.Right = interval;
1321             else
1322               Parent.Left = interval;
1323
1324             int diff = Length;
1325             if (interval != null)
1326               diff -= interval.Length;
1327             for (MInterval i = Parent; i != stop; i = i.Parent)
1328               i.Length -= diff;
1329           }
1330       }
1331
1332       public void Delete (int start, int end)
1333       {
1334         update_from_to ();
1335         M17n.DebugPrint ("delete({0} {1}) from {2}\n", start, end, this);
1336
1337         bool front_checked = false;
1338         bool rear_checked = false;
1339
1340         if (start < From)
1341           {
1342             if (end <= From)
1343               {
1344                 if (end == From && isFrontSensitive)
1345                   Stack.Clear ();
1346                 Left.Delete (start, end);
1347                 return;
1348               }
1349             if (isSensitive || isFrontSensitive)
1350               Stack.Clear ();
1351             Left.Delete (start, From);
1352             To -= From - start;
1353             end -= From - start;
1354             From = start;
1355             front_checked = true;
1356           }
1357         if (end > To)
1358           {
1359             if (start >= To)
1360               {
1361                 if (start == To && isRearSensitive)
1362                   Stack.Clear ();
1363                 Right.Delete (start, end);
1364                 return;
1365               }
1366             if (isSensitive || isRearSensitive)
1367               Stack.Clear ();
1368             Right.Delete (To, end);
1369             end = To;
1370             rear_checked = true;
1371           }
1372         if (start == From
1373             && ! front_checked
1374             && start > 0
1375             && isRearSensitive)
1376           Prev.Stack.Clear ();
1377         if (end == To
1378             && ! rear_checked
1379             && Next != null
1380             && isFrontSensitive)
1381           Next.Stack.Clear ();
1382         if (start == From && end == To)
1383           {
1384             if (Right == null)
1385               {
1386                 vacate_node (Left);
1387               }
1388             else
1389               {
1390                 if (Left != null)
1391                   {
1392                     MInterval i;
1393                 
1394                     for (i = Right; i.Left != null; i = i.Left)
1395                       i.Length += Left.Length;
1396                     i.Length += Left.Length;
1397                     i.Left = Left;
1398                     Left.Parent = i;
1399                   }
1400                 vacate_node (Right);
1401               }
1402           }
1403         else
1404           {
1405             int len = end - start;
1406
1407             if (isAnySensitive)
1408               Stack.Clear ();
1409             for (MInterval i = this; i != null; i = i.Parent)
1410               i.Length -= len;
1411           }
1412       }
1413
1414       public void Push (int start, int end, MProperty prop)
1415       {
1416         update_from_to ();
1417         M17n.DebugPrint ("push({0} {1}) at {2}\n", start, end, this);
1418         if (start < From)
1419           {
1420             if (end <= From)
1421               {
1422                 Left.Push (start, end, prop);
1423                 return;
1424               }
1425             Left.Push (start, From, prop);
1426             start = From;
1427           }
1428         if (end > To)
1429           {
1430             if (start >= To)
1431               {
1432                 Right.Push (start, end, prop);
1433                 return;
1434               }
1435             Right.Push (To, end, prop);
1436             end = To;
1437           }
1438
1439         if (! Stack.IsEmpty && isAnySensitive)
1440           Stack.Clear ();
1441         if (start > From)
1442           divide_left (start);
1443         if (end < To)
1444           divide_right (end);
1445         Stack.Push (prop.key, prop);
1446       }
1447
1448       /// Combine intervals between HEAD and TAIL (both inclusive) to
1449       /// the common parent of HEAD and TAIL.  Callers should assure
1450       /// that the intervals are mergeable in advance.
1451       private static void combine (MInterval head, MInterval tail)
1452       {
1453         M17n.DebugPrint ("combining {0} through {1}", head, tail);
1454
1455         head.update_from_to ();
1456         tail.update_from_to ();
1457         int from = head.From;
1458         int to = tail.To;
1459
1460         // The nearest common parent of HEAD and TAIL.
1461         MInterval root;
1462         for (root = head; root.To + root.RightLength < to;
1463              root = root.Parent);
1464         
1465         M17n.DebugPrint (" with common root {0}\n", root);
1466
1467         if (from < root.From)
1468           {
1469             MInterval prev = root.Prev;
1470
1471             while (true)
1472               {
1473                 M17n.DebugPrint ("merging {0}\n", prev);
1474                 prev.vacate_node (prev.Left, root);
1475                 if (prev == head)
1476                   break;
1477                 if (prev.Left != null)
1478                   prev = prev.Left.RightMost;
1479                 else
1480                   prev = prev.Parent;
1481               }
1482             root.update_from_to ();
1483           }
1484         if (root.To < to)
1485           {
1486             MInterval next = root.Next;
1487
1488             while (true)
1489               {
1490                 M17n.DebugPrint ("merging {0}\n", next);
1491                 next.vacate_node (next.Right, root);
1492                 if (next == tail)
1493                   break;
1494                 if (next.Right != null)
1495                   next = next.Right.LeftMost;
1496                 else
1497                   next = next.Parent;
1498               }
1499             root.update_from_to ();
1500           }
1501       }
1502
1503       public void MergeAfterChange (int start, int end)
1504       {
1505         update_from_to ();
1506
1507         MInterval head = find_head (start), i = head;
1508         MInterval tail = start < end ? find_tail (end) : head;
1509
1510         if (tail.To < Length)
1511           tail = tail.Next;
1512
1513         if (start == head.From && start > 0)
1514           {
1515             MInterval prev = head.Prev;
1516             if (head.mergeable (prev))
1517               head = prev;
1518           }
1519         M17n.DebugPrint ("merge between {0} and {1}\n", head, tail);
1520         while (i != tail)
1521           {
1522             MInterval next = i.Next;
1523
1524             if (! i.mergeable (next))
1525               {
1526                 if (head != i)
1527                   combine (head, i);
1528                 head = next;
1529               }
1530             i = next;
1531           }
1532         if (head != i)
1533           combine (head, i);
1534       }
1535
1536       public void Pop (int start, int end)
1537       {
1538         update_from_to ();
1539         M17n.DebugPrint ("pop({0} {1}) at {2}\n", start, end, this);
1540         if (start < From)
1541           {
1542             if (end <= From)
1543               {
1544                 Left.Pop (start, end);
1545                 return;
1546               }
1547             Left.Pop (start, From);
1548             start = From;
1549           }
1550         if (end > To)
1551           {
1552             if (start >= To)
1553               {
1554                 Right.Pop (start, end);
1555                 return;
1556               }
1557             Right.Pop (To, end);
1558             end = To;
1559           }
1560
1561         if (! Stack.IsEmpty)
1562           {
1563             if (isAnySensitive)
1564               Stack.Clear ();
1565             else
1566               {
1567                 if (start > From)
1568                   divide_left (start);
1569                 if (end < To)
1570                   divide_right (end);
1571                 Stack.Pop ();
1572               }
1573           }
1574       }
1575
1576       public void PopSensitive (int start, int end)
1577       {
1578         update_from_to ();
1579         MInterval head = find_head (start);
1580         MInterval tail = find_tail (end);
1581         while (! head.Stack.IsEmpty && head.From > 0)
1582           {
1583             MInterval prev = head.Prev;
1584
1585             if (prev.Stack.IsEmpty || head.Stack.Val != prev.Stack.Val)
1586               break;
1587             head = head.Prev;
1588           }
1589         while (! tail.Stack.IsEmpty && tail.To < mtext.Length)
1590           {
1591             MInterval next = tail.Next;
1592
1593             if (next.Stack.IsEmpty || tail.Stack.Val != next.Stack.Val)
1594               break;
1595             tail = tail.Next;
1596           }
1597         Pop (head.From, tail.To);
1598       }
1599
1600       public override string ToString ()
1601       {
1602         string str = String.Format ("#{0}({1} {2} {3} [", ID, Length, From, To);
1603         bool first = true;
1604         foreach (MPlist p in Stack)
1605           {
1606             if (first)
1607               {
1608                 str += ((MProperty) p.Val).Val;
1609                 first = false;
1610               }
1611             else
1612               str += " " + ((MProperty) p.Val).Val;
1613           }
1614         return (str + "])");
1615       }
1616
1617       private void DumpOne (bool with_prop, bool newline, bool force)
1618       {
1619         if (force || M17n.debug)
1620           {
1621             Console.Write ("#{0}({1} {2} {3}", ID, Length, From, To);
1622             if (with_prop && ! Stack.IsEmpty)
1623               {
1624                 string prepend = " [";
1625                 foreach (MPlist p in Stack)
1626                   {
1627                     Console.Write (prepend + ((MProperty) p.Val).Val);
1628                     prepend = " ";
1629                   }
1630                 Console.Write ("]");
1631               }
1632             Console.Write (")");
1633             if (newline)
1634               Console.WriteLine ();
1635             if (Length <= 0)
1636               throw new Exception ("Invalid interval length");
1637           }
1638       }
1639
1640       public void Dump () { Dump (false); }
1641
1642       public void Dump (bool force)
1643       {
1644         if (force || M17n.debug)
1645           {
1646             update_from_to ();
1647
1648             if (Left != null)
1649               Left.Dump (force);
1650             if (From > 0)
1651               Console.Write (" ");
1652             DumpOne (true, false, force);
1653             if (Right != null)
1654               Right.Dump (force);
1655           }
1656       }
1657
1658       private int Depth {
1659         get { return (Parent == null ? 0 : Parent.Depth + 1); }
1660       }
1661
1662       public void DumpNested (bool force)
1663       {
1664         DumpNested (Key.ToString () + ":", force);
1665       }
1666
1667       public void DumpNested (string indent, bool force)
1668       {
1669         if (force || M17n.debug)
1670           {
1671             int indent_type = (Parent == null ? 1
1672                                : Parent.Left == this ? 0 : 2);
1673
1674             update_from_to ();
1675             if (Left != null)
1676               {
1677                 if (indent_type <= 1)
1678                   Left.DumpNested (indent + "  ", force);
1679                 else
1680                   Left.DumpNested (indent + "| ", force);
1681               }
1682             Console.Write (indent);
1683             if (indent_type == 0)
1684               Console.Write (".-");
1685             else if (indent_type == 2)
1686               Console.Write ("`-");
1687             DumpOne (true, true, true);
1688             if (Right != null)
1689               {
1690                 if (indent_type >= 1)
1691                   Right.DumpNested (indent + "  ", force);
1692                 else
1693                   Right.DumpNested (indent + "| ", force);
1694               }
1695           }
1696       }
1697     }
1698
1699     private class MTextEnum : IEnumerator
1700     {
1701       private MText mt;
1702       private int pos = -1;
1703
1704       public MTextEnum (MText mt)
1705         {
1706           this.mt = mt;
1707         }
1708
1709       public bool MoveNext ()
1710       {
1711         pos++;
1712         return (pos < mt.nchars);
1713       }
1714
1715       public void Reset ()
1716       {
1717         pos = -1;
1718       }
1719
1720       public object Current
1721       {
1722         get {
1723           //if (pos < 0 || pos >= mt.nchars)
1724           //throw new InvalidOperationException ();
1725           return mt[pos];
1726         }
1727       }
1728     }
1729   }
1730 }