#if ENABLE_TESTS
using NUnit.Framework;
using System;
using Hyena;
using FSpot;

namespace FSpot.Database.Tests
{
    [TestFixture]
    public class UpdaterTests
    {
        static bool initialized = false;
        static void Initialize () {
            GLib.GType.Init ();
            Updater.silent = true;
            initialized = true;
        }

        [Test]
        public void Test_0_6_1_5 ()
        {
            TestUpdate ("0.6.1.5", "17.0");
        }

        [Test]
        public void Test_0_6_2 ()
        {
            TestUpdate ("0.6.2", "17.1");
        }

        [Test]
        public void Test_0_7_0_17_2 ()
        {
            TestUpdate ("0.7.0-17.2", "17.2");
        }

        [Test]
        public void Test_0_7_0_18_0 ()
        {
            TestUpdate ("0.7.0-18.0", "18");
        }

        private void TestUpdate (string version, string revision)
        {
            if (!initialized)
                Initialize ();

            var uri = new SafeUri (Environment.CurrentDirectory + "/../tests/data/f-spot-"+version+".db");
            var file = GLib.FileFactory.NewForUri (uri);
            Assert.IsTrue (file.Exists, String.Format ("Test database for version {0} not found", version));

            var tmp = System.IO.Path.GetTempFileName ();
            var uri2 = new SafeUri (tmp);
            var file2 = GLib.FileFactory.NewForUri (uri2);
            file.Copy (file2, GLib.FileCopyFlags.Overwrite, null, null);

            var db = new FSpotDatabaseConnection (uri2.AbsolutePath);
            ValidateRevision (db, revision);

            Updater.Run (db);
            ValidateRevision (db, Updater.LatestVersion.ToString ());

            ValidateTableStructure (db);

            CheckPhotosTable (db);
            CheckPhotoVersionsTable (db);
            CheckTagsTable (db);

            file2.Delete ();
        }

        private void ValidateRevision (FSpotDatabaseConnection db, string revision)
        {
            var query = "SELECT data FROM meta WHERE name = 'F-Spot Database Version'";
            var found = db.Query<string> (query).ToString ();
            Assert.AreEqual (revision, found);
        }

        private void ValidateTableStructure (FSpotDatabaseConnection db)
        {
            CheckTableExistance (db, "exports");
            CheckTableExistance (db, "jobs");
            CheckTableExistance (db, "meta");
            CheckTableExistance (db, "photo_tags");
            CheckTableExistance (db, "photo_versions");
            CheckTableExistance (db, "photos");
            CheckTableExistance (db, "rolls");
            CheckTableExistance (db, "tags");
        }

        private void CheckTableExistance (FSpotDatabaseConnection db, string name)
        {
            Assert.IsTrue (db.TableExists (name), String.Format ("Expected table {0} does not exist.", name));
        }

        private void CheckPhotosTable (FSpotDatabaseConnection db)
        {
            CheckPhoto (db, 1, 1249579156, "file:///tmp/database/", "sample.jpg", "Testing!", 1, 2, 5);
            CheckPhoto (db, 2, 1276191607, "file:///tmp/database/", "sample_canon_bibble5.jpg", "", 1, 1, 0);
            CheckPhoto (db, 3, 1249834364, "file:///tmp/database/", "sample_canon_zoombrowser.jpg", "%test comment%", 1, 1, 0);
            CheckPhoto (db, 4, 1276191607, "file:///tmp/database/", "sample_gimp_exiftool.jpg", "", 1, 1, 5);
            CheckPhoto (db, 5, 1242995279, "file:///tmp/database/", "sample_nikon1.jpg", "", 1, 1, 1);
            CheckPhoto (db, 6, 1276191607, "file:///tmp/database/", "sample_nikon1_bibble5.jpg", "", 1, 1, 0);
            CheckPhoto (db, 7, 1167646774, "file:///tmp/database/", "sample_nikon2.jpg", "", 1, 1, 0);
            CheckPhoto (db, 8, 1276191607, "file:///tmp/database/", "sample_nikon2_bibble5.jpg", "", 1, 1, 0);
            CheckPhoto (db, 9, 1256140553, "file:///tmp/database/", "sample_nikon3.jpg", "                                    ", 1, 1, 0);
            CheckPhoto (db, 10, 1238587697, "file:///tmp/database/", "sample_nikon4.jpg", "                                    ", 1, 1, 0);
            CheckPhoto (db, 11, 1276191607, "file:///tmp/database/", "sample_no_metadata.jpg", "", 1, 1, 0);
            CheckPhoto (db, 12, 1265446642, "file:///tmp/database/", "sample_null_orientation.jpg", "", 1, 1, 0);
            CheckPhoto (db, 13, 1161575860, "file:///tmp/database/", "sample_olympus1.jpg", "", 1, 1, 0);
            CheckPhoto (db, 14, 1236006332, "file:///tmp/database/", "sample_olympus2.jpg", "", 1, 1, 0);
            CheckPhoto (db, 15, 1246010310, "file:///tmp/database/", "sample_panasonic.jpg", "", 1, 1, 0);
            CheckPhoto (db, 16, 1258799979, "file:///tmp/database/", "sample_sony1.jpg", "", 1, 1, 0);
            CheckPhoto (db, 17, 1257533767, "file:///tmp/database/", "sample_sony2.jpg", "", 1, 1, 0);
            CheckPhoto (db, 18, 1026565108, "file:///tmp/database/", "sample_xap.jpg", "", 1, 1, 4);
            CheckPhoto (db, 19, 1093249257, "file:///tmp/database/", "sample_xmpcrash.jpg", "", 1, 1, 0);
            CheckPhoto (db, 20, 1276191607, "file:///tmp/database/test/", "sample_tangled1.jpg", "test comment", 1, 1, 0);
            CheckCount (db, "photos", 20);
        }

        private void CheckPhotoVersionsTable (FSpotDatabaseConnection db)
        {
            CheckPhotoVersion (db, 1, 1, "Original", "file:///tmp/database/", "sample.jpg", "", 1);
            CheckPhotoVersion (db, 2, 1, "Original", "file:///tmp/database/", "sample_canon_bibble5.jpg", "", 1);
            CheckPhotoVersion (db, 3, 1, "Original", "file:///tmp/database/", "sample_canon_zoombrowser.jpg", "", 1);
            CheckPhotoVersion (db, 4, 1, "Original", "file:///tmp/database/", "sample_gimp_exiftool.jpg", "", 1);
            CheckPhotoVersion (db, 5, 1, "Original", "file:///tmp/database/", "sample_nikon1.jpg", "", 1);
            CheckPhotoVersion (db, 6, 1, "Original", "file:///tmp/database/", "sample_nikon1_bibble5.jpg", "", 1);
            CheckPhotoVersion (db, 7, 1, "Original", "file:///tmp/database/", "sample_nikon2.jpg", "", 1);
            CheckPhotoVersion (db, 8, 1, "Original", "file:///tmp/database/", "sample_nikon2_bibble5.jpg", "", 1);
            CheckPhotoVersion (db, 9, 1, "Original", "file:///tmp/database/", "sample_nikon3.jpg", "", 1);
            CheckPhotoVersion (db, 10, 1, "Original", "file:///tmp/database/", "sample_nikon4.jpg", "", 1);
            CheckPhotoVersion (db, 1, 2, "Modified", "file:///tmp/database/", "sample%20(Modified).jpg", "", 0);
            CheckPhotoVersion (db, 11, 1, "Original", "file:///tmp/database/", "sample_no_metadata.jpg", "", 1);
            CheckPhotoVersion (db, 12, 1, "Original", "file:///tmp/database/", "sample_null_orientation.jpg", "", 1);
            CheckPhotoVersion (db, 13, 1, "Original", "file:///tmp/database/", "sample_olympus1.jpg", "", 1);
            CheckPhotoVersion (db, 14, 1, "Original", "file:///tmp/database/", "sample_olympus2.jpg", "", 1);
            CheckPhotoVersion (db, 15, 1, "Original", "file:///tmp/database/", "sample_panasonic.jpg", "", 1);
            CheckPhotoVersion (db, 16, 1, "Original", "file:///tmp/database/", "sample_sony1.jpg", "", 1);
            CheckPhotoVersion (db, 17, 1, "Original", "file:///tmp/database/", "sample_sony2.jpg", "", 1);
            CheckPhotoVersion (db, 18, 1, "Original", "file:///tmp/database/", "sample_xap.jpg", "", 1);
            CheckPhotoVersion (db, 19, 1, "Original", "file:///tmp/database/", "sample_xmpcrash.jpg", "", 1);
            CheckPhotoVersion (db, 20, 1, "Original", "file:///tmp/database/test/", "sample_tangled1.jpg", "", 1);
            CheckCount (db, "photo_versions", 21);
            CheckOriginalVersionCount (db);
        }

        private void CheckTagsTable (FSpotDatabaseConnection db)
        {
            CheckTag (db, 1, "Favorites", 0, 1, -10, "stock_icon:emblem-favorite");
            CheckTag (db, 2, "Hidden", 0, 0, -9, "stock_icon:emblem-readonly");
            CheckTag (db, 3, "People", 0, 1, -8, "stock_icon:emblem-people");
            CheckTag (db, 4, "Places", 0, 1, -8, "stock_icon:emblem-places");
            CheckTag (db, 5, "Events", 0, 1, -7, "stock_icon:emblem-event");
            CheckTag (db, 6, "Imported Tags", 0, 1, 0, "stock_icon:gtk-new");
            CheckTag (db, 7, "keyword1", 6, 1, 0, "");
            CheckTag (db, 8, "keyword2", 6, 1, 0, "");
            CheckTag (db, 9, "keyword3", 6, 1, 0, "");
            CheckTag (db, 10, "keyword 1", 6, 1, 0, "");
            CheckTag (db, 11, "keyword 2", 6, 1, 0, "");
            CheckTag (db, 12, "Kirche Sulzbach", 6, 1, 0, "");
            CheckTag (db, 13, "Nikon D70s", 6, 1, 0, "");
            CheckTag (db, 14, "Food", 6, 1, 0, "");
            CheckTag (db, 15, "2007", 6, 1, 0, "");
            CheckTag (db, 16, "2006", 6, 1, 0, "");
            CheckTag (db, 17, "Neujahr", 6, 1, 0, tag_icon_emblem);
            CheckTag (db, 18, "Sylvester", 6, 1, 0, "");
            CheckTag (db, 19, "Olympus µ 700", 6, 1, 0, "");
            CheckTag (db, 20, "Rom 2006-10", 6, 1, 0, "");
            CheckTag (db, 21, "Architecture", 5, 1, 0, tag_icon_img);
            CheckTag (db, 22, "Flughafen", 6, 1, 0, "");
            CheckTag (db, 23, "Basel", 6, 1, 0, "");
            CheckTag (db, 24, "FreeFoto.com", 6, 1, 0, "");
            CheckTag (db, 25, "City", 6, 1, 0, "stock_icon:emblem-places");
            CheckTag (db, 26, " ", 25, 1, 0, "");
            CheckTag (db, 27, "State", 6, 1, 0, "stock_icon:emblem-places");
            CheckTag (db, 28, "Country", 6, 1, 0, "stock_icon:emblem-places");
            CheckTag (db, 29, "Ubited Kingdom", 28, 1, 0, "");
            CheckTag (db, 30, "Communications", 6, 1, 0, "");
            CheckTag (db, 31, "Türkei 2004", 6, 1, 0, "");
            CheckCount (db, "tags", 31);
        }

        private void CheckPhoto (FSpotDatabaseConnection db, uint id, uint time, string base_uri, string filename, string description, uint roll_id, uint default_version_id, uint rating)
        {
            var reader = db.Query ("SELECT id, time, base_uri, filename, description, roll_id, default_version_id, rating FROM photos WHERE id = " + id);
            var found = false;
            while (reader.Read ()) {
                Assert.AreEqual (id, Convert.ToUInt32 (reader[0]), "id on photo "+id);
                Assert.AreEqual (time, Convert.ToUInt32 (reader[1]), "time on photo "+id);
                Assert.AreEqual (base_uri, reader[2], "base_uri on photo "+id);
                Assert.AreEqual (filename, reader[3], "filename on photo "+id);
                Assert.AreEqual (description, reader[4], "description on photo "+id);
                Assert.AreEqual (roll_id, Convert.ToUInt32 (reader[5]), "roll_id on photo "+id);
                Assert.AreEqual (default_version_id, Convert.ToUInt32 (reader[6]), "default_version_id on photo "+id);
                Assert.AreEqual (rating, Convert.ToUInt32 (reader[7]), "rating on photo "+id);
                found = true;
            }
            Assert.IsTrue (found, "photo "+id+" missing");
        }

        private void CheckPhotoVersion (FSpotDatabaseConnection db, uint photo_id, uint version_id, string name, string base_uri, string filename, string import_md5, uint is_protected)
        {
            var reader = db.Query ("SELECT photo_id, version_id, name, base_uri, filename, import_md5, protected FROM photo_versions WHERE photo_id = " + photo_id + " AND version_id = " + version_id);
            var found = false;
            while (reader.Read ()) {
                Assert.AreEqual (photo_id, Convert.ToUInt32 (reader[0]), "photo_id on photo version "+photo_id+"/"+version_id);
                Assert.AreEqual (version_id, Convert.ToUInt32 (reader[1]), "version_id on photo version "+photo_id+"/"+version_id);
                Assert.AreEqual (name, reader[2], "name on photo version "+photo_id+"/"+version_id);
                Assert.AreEqual (base_uri, reader[3], "base_uri on photo version "+photo_id+"/"+version_id);
                Assert.AreEqual (filename, reader[4], "filename on photo version "+photo_id+"/"+version_id);
                Assert.AreEqual (import_md5, reader[5], "import_md5 on photo version "+photo_id+"/"+version_id);
                Assert.AreEqual (is_protected, Convert.ToUInt32 (reader[6]), "protected on photo version "+photo_id+"/"+version_id);
                found = true;
            }
            Assert.IsTrue (found, "photo version "+photo_id+"/"+version_id+" missing");
        }

        private void CheckOriginalVersionCount (FSpotDatabaseConnection db)
        {
            var photo_count = GetCount (db, "photos", "1");
            var orig_version_count = GetCount (db, "photo_versions", "version_id = 1");
            Assert.AreEqual (photo_count, orig_version_count, "Expecting an original version for each photo");
        }

        private void CheckTag (FSpotDatabaseConnection db, uint id, string name, uint cat_id, int is_cat, int sort, string icon)
        {
            var reader = db.Query ("SELECT id, name, category_id, is_category, sort_priority, icon FROM tags WHERE id = " + id);
            var found = false;
            while (reader.Read ()) {
                Assert.AreEqual (id, Convert.ToUInt32 (reader[0]), "id on tag "+id);
                Assert.AreEqual (name, reader[1], "name on tag "+id);
                Assert.AreEqual (cat_id, Convert.ToUInt32 (reader[2]), "category_id on tag "+id);
                Assert.AreEqual (is_cat, Convert.ToInt32 (reader[3]), "is_cat on tag "+id);
                Assert.AreEqual (sort, reader[4], "sort_priority on tag "+id);
                Assert.AreEqual (icon, reader[5], "icon on tag "+id);
                found = true;
            }
            Assert.IsTrue (found, "tag "+id+" missing");
        }

        private int GetCount (FSpotDatabaseConnection db, string table, string where)
        {
            return db.Query<int> ("SELECT COUNT(*) FROM "+table+" WHERE "+where);
        }

        private void CheckCount (FSpotDatabaseConnection db, string table, int count)
        {
            var counted = GetCount (db, table, "1");
            Assert.AreEqual (count, counted, "Count on "+table);
        }

        private const string tag_icon_img = "[encoded data, 12320 characters]";

        private const string tag_icon_emblem = "[encoded data, 9248 characters]";
    }
}
#endif
