*** empty log message ***
[m17n/m17n-lib-cs.git] / MDatabase.cs
index ef545c5..798599f 100644 (file)
@@ -28,7 +28,8 @@ namespace M17N.Core
        Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = MSymbol.nil;
       }
 
-    public MDatabaseTag (MSymbol tag0, MSymbol tag1, MSymbol tag2, MSymbol tag3)
+    public MDatabaseTag (MSymbol tag0, MSymbol tag1,
+                        MSymbol tag2, MSymbol tag3)
       {
        Tag0 = tag0; Tag1 = tag1; Tag2 = tag2; Tag3 = tag3;
       }
@@ -36,18 +37,126 @@ namespace M17N.Core
 
   public class MDatabase
   {
+    private class MDatabaseDir
+    {
+      private const string ListFileName = "mdb.dir";
+
+      public string Dirname;
+      public DirectoryInfo DirInfo;
+      public DateTime LastScanned;
+      public FileInfo ListInfo;
+
+      private static void GetInfo (string dirname, out DirectoryInfo dirinfo,
+                                  out FileInfo listinfo)
+      {
+       if (Directory.Exists (dirname))
+         try { dirinfo = new DirectoryInfo (dirname);
+           try { listinfo = dirinfo.GetFiles (ListFileName)[0];
+           } catch { listinfo = null; }
+         } catch { dirinfo = null; listinfo = null; }
+       else
+         {
+           dirinfo = null;
+           listinfo = null;
+         }
+      }
+
+      public MDatabaseDir (string dirname)
+      {
+       Dirname = dirname;
+       GetInfo (dirname, out DirInfo, out ListInfo);
+      }
+
+      public bool StatusChanged {
+       get {
+         bool exists = Directory.Exists (Dirname);
+
+         if (DirInfo != null)
+           {
+             if (! exists)
+               {
+                 DirInfo = null;
+                 ListInfo = null;
+                 LastScanned = new DateTime (0);
+               }
+             if (LastScanned.Year == 0)
+               return true;
+             DirInfo.Refresh ();
+             if (ListInfo != null)
+               ListInfo.Refresh ();
+             return (LastScanned < DirInfo.LastWriteTime
+                     || LastScanned < ListInfo.LastWriteTime);
+           }
+         else
+           {
+             if (exists)
+               {
+                 DirInfo = new DirectoryInfo (Dirname);
+                 try {
+                   ListInfo = DirInfo.GetFiles (ListFileName)[0];
+                 } catch {
+                   ListInfo = null;
+                 }
+                 return true;
+               }
+             return false;
+           }
+       }
+      }
+
+      public void UpdateStatus ()
+      {
+       if (DirInfo != null)
+         LastScanned = DateTime.UtcNow;
+      }
+
+      public FileInfo[] Scan (string filename)
+      {
+       if (DirInfo == null)
+         return null;
+       DirInfo.Refresh ();
+       return DirInfo.GetFiles (filename);
+      }
+    }
+
+    internal class MDatabaseInfo {
+      internal DirectoryInfo Dir;
+      internal string Description;
+      internal MText Filename;
+      internal FileInfo FileInfo;
+      internal FileInfo Validater;
+      internal int Version;
+      internal MSymbol Format;
+      internal MSymbol Schema;
+      internal MText SchemaFile;
+      internal DateTime ModifiedTime;
+      internal MPlist Props;
+    }
+
+    private static Dictionary<MDatabaseTag, MDatabase> DBDict
+      = new Dictionary<MDatabaseTag, MDatabase> ();
+
+    private static MDatabaseDir[] DBDirs = new MDatabaseDir[3];
+
+    private const string SystemDirectory = "/usr/share/m17n";
+    private readonly MSymbol Mversion = MSymbol.Of ("version");
+
     /// Type of database
     private enum MDBType
       {
-       /// The database was defined automatically (from mdb.dir
-       /// file(s)) with no wildcard tag.
+       /// The database was defined automatically from mdb.dir
+       /// file(s) with no wildcard tag.
        AUTO,
-       /// The database was defined automatically (from mdb.dir
-       /// file(s)) with a wildcard tag to define multiple databases
+       /// The database was defined automatically from mdb.dir
+       /// file(s) with a wildcard tag to define multiple databases
        /// of the same kind.
-       AUTO_WILDCARD,
-       /// The database was defined explicitely (by MDatabaseDefine).
-       EXPLICIT
+       MULTIPLE,
+       /// The database was defined explicitely by MDatabase.Define
+       /// without a special loader.
+       EXPLICIT,
+       /// The database was defined explicitely by MDatabase.Define
+       /// with a special loader.
+       UNKNOWN,
       };
 
     /// Status of database
@@ -63,65 +172,186 @@ namespace M17N.Core
        // The database file has not been modified after the previous
        // loading.
        UPDATED,
-       // The database file is updated but the validation was failed.
-       // If this is for a database directory, the directory is
-       // readable but "mdb.dir" doesn't exist in it.
-       INVALID
+       // The database file is updated but the validation was failed
+       // or the version is not supported by the current system.
+       INVALID,
       };
 
-    private static Dictionary<MDatabaseTag, MDatabase> db_dict
-      = new Dictionary<MDatabaseTag, MDatabase> ();
-
-    private MDatabaseTag tag;
-    private MDatabaseLoader loader;
-    private object extra_info;
-
-    private bool system_database;
-    private DirectoryInfo dir;
-    private FileInfo file;
-    private FileInfo validater;
-    private int major_version, minor_version, release_number;
-    private MDBType type;
-    private MDBStatus status;
-    private MSymbol format;
-    private MSymbol schema;
-    private DateTime mtime;
-    private DateTime ltime;
-    private MPlist props;
+    public readonly MDatabaseTag Tag;
+    private MDatabaseLoader Loader;
+    private object ExtraInfo;
+    private MDBType DBType;
+    private MDBStatus DBStatus;
+    internal DateTime LoadedTime;
+    internal MDatabaseInfo Info;
 
     public static string ApplicationDirectory;
 
-    public MDatabase (MDatabaseTag tag, MDatabaseLoader loader,
+    private MDatabase (MDatabaseTag tag, MDatabaseLoader loader,
                      object extra_info)
     {
-      this.tag = tag;
-      this.loader = loader;
-      this.extra_info = extra_info;
+      Tag = tag;
+      Loader = loader;
+      ExtraInfo = extra_info;
     }
 
-    public MDatabase (MDatabaseTag tag, string filename)
+    private MDatabase (MDatabaseTag tag, string filename)
     {
-      this.tag = tag;
-      this.loader = load;
+      Tag = tag;
+      Info = new MDatabaseInfo ();
+      Info.Filename = new MText (filename);
     }
 
-    public MDatabaseTag Tag { get { return tag; } }
+    private MDatabase (MPlist plist)
+    {
+      MSymbol[] tags = new MSymbol[4];
+      int i;
+
+      for (i = 0; plist.IsSymbol; i++, plist = plist.Next)
+       tags[i] = plist.Symbol;
+      while (i < 4)
+       tags[i++] = MSymbol.nil;
+      Tag = new MDatabaseTag (tags[0], tags[1], tags[2], tags[3]);
+      if (plist.IsMText)
+       {
+         Info.Filename = plist.Text;
+         plist = plist.Next;
+       }
+      else if (plist.IsPlist)
+       {
+         MPlist p = plist.Plist;
+
+         if (p.IsMText)
+           Info.Filename = plist.Text;
+         p = p.Next;
+         if (! p.IsEmpty)
+           {
+             if (p.IsSymbol)
+               Info.Format = p.Symbol;
+             p = p.Next;
+             if (! p.IsEmpty)
+               {
+                 if (p.IsSymbol)
+                   Info.Schema = p.Symbol;
+                 p = p.Next;
+                 if (p.IsMText)
+                   Info.SchemaFile = p.Text;
+               }                   
+           }
+         plist = plist.Next;
+       }
+      DBStatus = MDBStatus.OUTDATED;;
+      Info.Version = 0;
+      Info.Props = new MPlist ();
+      foreach (MPlist pl in plist)
+       {
+         if (pl.IsPlist)
+           {
+             MPlist p = pl.Plist;
+             
+             if (p.IsSymbol && p.Symbol == Mversion)
+               {
+                 Info.Version = parse_version (p.Next);
+                 if (M17n.Version < Info.Version)
+                   DBStatus = MDBStatus.DISABLED;
+               }
+           }
+         Info.Props.Put (pl.Key, pl.Val);
+       }
+    }
+
+    private static int parse_version (MPlist plist)
+    {
+      string[] str;
+      int major, minor, release;
+
+      if (! plist.IsMText)
+       return 0xFFFFFF;
+      str = plist.Text.ToString ().Split ('.');
+      if (str.Length != 3)
+       return 0xFFFFFF;
+      try { major = int.Parse (str[0]); } catch { return 0xFFFFFF; }
+      try { minor = int.Parse (str[1]); } catch { return 0xFFFFFF; }
+      try { release = int.Parse (str[2]); } catch { return 0xFFFFFF; }
+      return ((major << 16) | (minor << 8) | release);
+    }
+
+    public static MDatabase Define (MDatabaseTag tag, MDatabaseLoader loader,
+                                   object extra_info)
+    {
+      MDatabase db = MDatabase.Find (tag);
+
+      if (db != null)
+       {
+         db.Loader = loader;
+         db.ExtraInfo = extra_info;
+         db.DBType = MDBType.EXPLICIT;
+         db.DBStatus = MDBStatus.OUTDATED;
+         db.Info = null;
+         return db;
+       }
+      return new MDatabase (tag, loader, extra_info);
+    }
+
+    public static  MDatabase Define (MDatabaseTag tag, string filename)
+    {
+      MDatabase db = MDatabase.Find (tag);
+
+      if (db != null)
+       {
+         db.Loader = null;
+         db.DBType = MDBType.EXPLICIT;
+         db.DBStatus = MDBStatus.OUTDATED;
+         db.Info = new MDatabaseInfo ();
+         db.Info.Filename = new MText (filename);
+
+         return db;
+       }
+      return new MDatabase (tag, filename);
+    }
+
+    static MDatabase ()
+    {
+      string share_dir = (Environment.GetFolderPath
+                         (Environment.SpecialFolder.CommonApplicationData));
+      string usr_dir = (Environment.GetFolderPath
+                       (Environment.SpecialFolder.ApplicationData));
+
+      try {
+       DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, ".m17n.d"));
+      } catch (ArgumentException) {
+       DBDirs[0] = new MDatabaseDir (Path.Combine (usr_dir, "_m17n_d"));
+      }
+      DBDirs[1] = null;
+      DBDirs[2] = new MDatabaseDir (Path.Combine (share_dir, "m17n"));
+    }
 
     public static MDatabase Find (MDatabaseTag tag)
     {
       MDatabase db;
 
-      return (db_dict.TryGetValue (tag, out db) ? db : null);
+      return (DBDict.TryGetValue (tag, out db) ? db : null);
     }
 
     public object Load ()
     {
-      return loader (tag, extra_info);
+      return (Loader != null ? Loader (Tag, ExtraInfo)
+             : load (MSymbol.nil, MSymbol.nil));
+    }
+
+    public object Load (MSymbol key, MSymbol stop)
+    {
+      if (Loader != null)
+       return null;
+      return load (key, stop);
     }
 
-    private object load (MDatabaseTag tag, object extra_info)
+    private object load (MSymbol key, MSymbol stop)
     {
-      ltime = DateTime.Now;
+      LoadedTime = DateTime.UtcNow;
+
+      
+
       return null;
     }