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