5b655684825530bcdc4f4340ac8d42b2008f92aa
[m17n/m17n-lib-cs.git] / MDatabase.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using M17N;
5 using M17N.Core;
6
7 namespace M17N.Core
8 {
9   public delegate object MDatabaseLoader (MDatabaseTag tag,
10                                           object extra_info);
11
12   public struct MDatabaseTag
13   {
14     public MSymbol Tag0, Tag1, Tag2, Tag3;
15
16     public MDatabaseTag (MSymbol tag0)
17       {
18         Tag0 = tag0; Tag1 = Tag2 = Tag3 = MSymbol.nil;
19       }
20
21     public MDatabaseTag (MSymbol tag0, MSymbol tag1)
22       {
23         Tag0 = tag0; Tag1 = tag1; Tag2 = Tag3 = MSymbol.nil;
24       }
25
26     public MDatabaseTag (MSymbol tag0, MSymbol tag1, MSymbol tag2)
27       {
28         Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = MSymbol.nil;
29       }
30
31     public MDatabaseTag (MSymbol tag0, MSymbol tag1,
32                          MSymbol tag2, MSymbol tag3)
33       {
34         Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = tag3;
35       }
36   }
37
38   public class MDatabase
39   {
40     private class MDatabaseDir
41     {
42       public string Dirname;
43       public DirectoryInfo Info;
44       public DateTime LastScanned;
45
46       public MDatabaseDir (string dirname)
47       {
48         Dirname = dirname;
49         try {
50           Info = new DirectoryInfo (dirname);
51         } finally {
52           Info = null;
53         }
54       }
55
56       public bool StatusChanged {
57         get {
58           bool exists = Directory.Exists (Dirname);
59
60           if (Info != null)
61             {
62               if (! exists)
63                 {
64                   Info = null;
65                   return true;
66                 }
67               Info.Refresh ();
68               return (LastScanned < Info.LastWriteTime);
69             }
70           else
71             {
72               if (exists)
73                 {
74                   Info = new DirectoryInfo (Dirname);
75                   return true;
76                 }
77               return false;
78             }
79         }
80       }
81
82       public void UpdateStatus ()
83       {
84         LastScanned = DateTime.Now;
85       }
86     }
87
88     private class MDatabaseDefinition
89     {
90       private static readonly MSymbol Mversion;
91       public MDatabaseTag Tag;
92       public string Description;
93       public MText Filename;
94       public bool IsWildcard;
95       public MSymbol Format;
96       public MSymbol Schema;
97       public MText SchemaFile;
98       public MPlist props;
99       public bool Supported;
100
101       static MDatabaseDefinition ()
102       {
103         Mversion = new MSymbol ("version");
104       }
105
106       public MDatabaseDefinition (MPlist plist)
107       {
108         MSymbol[] tags = new MSymbol[4];
109         int i;
110
111         for (i = 0; plist.IsSymbol; i++, plist = plist.Next)
112           tags[i] = plist.Symbol;
113         while (i < 4)
114           tags[i++] = MSymbol.nil;
115         Tag = new MDatabaseTag (tags[0], tags[1], tags[2], tags[3]);
116         if (plist.IsMText)
117           {
118             Filename = plist.Text;
119             plist = plist.Next;
120           }
121         else if (plist.IsPlist)
122           {
123             MPlist p = plist.Plist;
124
125             if (p.IsMText)
126               Filename = plist.Text;
127             p = p.Next;
128             if (! p.IsEmpty)
129               {
130                 if (p.IsSymbol)
131                   Format = p.Symbol;
132                 p = p.Next;
133                 if (! p.IsEmpty)
134                   {
135                     if (p.IsSymbol)
136                       Schema = p.Symbol;
137                     p = p.Next;
138                     if (p.IsMText)
139                       SchemaFile = p.Text;
140                   }                 
141               }
142             plist = plist.Next;
143           }
144         Supported = true;
145         props = new MPlist ();
146         foreach (MPlist pl in plist)
147           {
148             if (pl.IsPlist)
149               {
150                 MPlist p = pl.Plist;
151               
152                 if (p.IsSymbol && p.Symbol == Mversion
153                     && ! check_version (p.Next))
154                   Supported = false;
155                 props.Put (pl);
156               }
157           }
158       }
159
160       private bool check_version (MPlist plist)
161       {
162         string[] str;
163         int major, minor, release;
164
165         if (! plist.IsMText)
166           return false;
167         str = plist.Text.ToString ().Split ('.');
168         if (str.Length != 3)
169           return false;
170         try { major = int.Parse (str[0]); } catch { return false; }
171         try { minor = int.Parse (str[1]); } catch { return false; }
172         try { release = int.Parse (str[2]); } catch { return false; }
173         return (M17N.MajorVersion > major
174                 || (M17N.MajorVersion == major
175                     && (M17N.MinorVersion > minor
176                         || (M17N.MinorVersion == minor
177                             && M17N.ReleaseNumber >= release))));
178       }
179     }
180
181     private static MDatabaseDir[] DBDirs = new MDatabaseDir[3];
182
183     private const string SystemDirectory = "/usr/share/m17n";
184
185     private static Dictionary<MDatabaseTag, MDatabase> DBDict
186       = new Dictionary<MDatabaseTag, MDatabase> ();
187
188     /// Type of database
189     private enum MDBType
190       {
191         /// The database was defined automatically (from mdb.dir
192         /// file(s)) with no wildcard tag.
193         AUTO,
194         /// The database was defined automatically (from mdb.dir
195         /// file(s)) with a wildcard tag to define multiple databases
196         /// of the same kind.
197         AUTO_WILDCARD,
198         /// The database was defined explicitely (by MDatabaseDefine).
199         EXPLICIT
200       };
201
202     /// Status of database
203     private enum MDBStatus
204       {
205         // The database file is currently disabled.  It means that the
206         // database file is not readable or the database is deleted by
207         // the modification of "mdb.dir".
208         DISABLED,
209         // The database file has not yet been loaded, or was modified
210         // after the previous loading.
211         OUTDATED,
212         // The database file has not been modified after the previous
213         // loading.
214         UPDATED,
215         // The database file is updated but the validation was failed.
216         // If this is for a database directory, the directory is
217         // readable but "mdb.dir" doesn't exist in it.
218         INVALID
219       };
220
221     public readonly MDatabaseTag Tag;
222     private MDatabaseLoader Loader;
223     private object ExtraInfo;
224
225     private bool IsSystemDatabase;
226     private DirectoryInfo Dir;
227     private MText Filename;
228     private FileInfo FileInfo;
229     private FileInfo Validater;
230     private int MajorVersion, MinorVersion, ReleaseNumber;
231     private MDBType DBType;
232     private MDBStatus DBStatus;
233     private MSymbol Format;
234     private MSymbol Schema;
235     private DateTime Mtime;
236     private DateTime Ltime;
237     private MPlist Props;
238
239     public static string ApplicationDirectory;
240
241     private MDatabase (MDatabaseTag tag, MDatabaseLoader loader,
242                       object extra_info)
243     {
244       Tag = tag;
245       Loader = loader;
246       ExtraInfo = extra_info;
247     }
248
249     private MDatabase (MDatabaseTag tag, string filename)
250     {
251       Tag = tag;
252       Filename = new MText (filename);
253     }
254
255     public static MDatabase Define (MDatabaseTag tag, MDatabaseLoader loader,
256                                     object extra_info)
257     {
258       MDatabase db = MDatabase.Find (tag);
259
260       if (db != null)
261         {
262           db.Loader = loader;
263           db.ExtraInfo = extra_info;
264           return db;
265         }
266       return new MDatabase (tag, loader, extra_info);
267     }
268
269     public static  MDatabase Define (MDatabaseTag tag, string filename)
270     {
271       MDatabase db = MDatabase.Find (tag);
272
273       if (db != null)
274         {
275           db.Loader = null;
276           db.Filename = new MText (filename);
277           return db;
278         }
279       return new MDatabase (tag, filename);
280     }
281
282     static MDatabase ()
283     {
284       string share_dir = (Environment.GetFolderPath
285                           (Environment.SpecialFolder.CommonApplicationData));
286       string usr_dir = (Environment.GetFolderPath
287                         (Environment.SpecialFolder.ApplicationData));
288
289       try {
290         DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, ".m17n.d"));
291       } catch (ArgumentException) {
292         DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, "_m17n.d"));
293       }
294       DBDirs[1] = null;
295       DBDirs[2] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
296     }
297
298     internal static void Update ()
299     {
300
301     }
302
303
304     public static MDatabase Find (MDatabaseTag tag)
305     {
306       MDatabase db;
307
308       return (DBDict.TryGetValue (tag, out db) ? db : null);
309     }
310
311     public object Load ()
312     {
313       return (Loader != null ? Loader (Tag, ExtraInfo)
314               : load (MSymbol.nil, MSymbol.nil));
315     }
316
317     public object Load (MSymbol key, MSymbol stop)
318     {
319       if (Loader != null)
320         return null;
321       return load (key, stop);
322     }
323
324     private object load (MSymbol key, MSymbol stop)
325     {
326       Ltime = DateTime.Now;
327
328       
329
330       return null;
331     }
332
333   }
334
335 }