public IEnumerable<AnalysisTaxonomicGroup> GetAnalysisTaxonomicGroupsForProject(int projectID, UserCredentials login)
        {
            using (var db = login.GetConnection())
            {
                var atgs = new Queue<AnalysisTaxonomicGroup>(analysisTaxonomicGroupsForProject(projectID,db));                    
                var flattened = new HashSet<AnalysisTaxonomicGroup>();
                var analyses = analysesForProject(projectID,db).ToLookup(an => an.AnalysisParentID);

                while (atgs.Any())
                {
                    var atg = atgs.Dequeue();                    
                    if (flattened.Add(atg)) //added just now -> queue children
                    {
                        if (analyses.Contains(atg.AnalysisID))
                            foreach (var child in analyses[atg.AnalysisID])
                                atgs.Enqueue(
                                    new AnalysisTaxonomicGroup()
                                    {
                                        AnalysisID = child.AnalysisID,
                                        TaxonomicGroup = atg.TaxonomicGroup
                                    });
                    }
                }
                return flattened;
            }
        }
 public IEnumerable<EventProperty> PropertiesForEvent(int collectionEventID, UserCredentials login)
 {
     using (var db = login.GetConnection())
     {
         return db.Query<EventProperty>("WHERE CollectionEventID=@0", collectionEventID).ToList();
     }
 }
 public IEnumerable<Specimen> SpecimenForEvent(int collectionEventID, UserCredentials login)
 {
     using (var db = login.GetConnection())
     {
         return db.Query<Specimen>("WHERE CollectionEventID=@0", collectionEventID).ToList();
     }
 }
 public EventSeries EventSeriesByID(int collectionSeriesID, UserCredentials login)
 {
     using (var db = login.GetConnection())
     {
         return db.Single<EventSeries>(collectionSeriesID);
     }
 }
        public int InsertEvent(Event ev, IEnumerable<EventProperty> properties, UserCredentials login)
        {
            using (var db = login.GetConnection())
            using (var t = new Transaction(db))
            {
                db.Insert(ev);

                var geoString = SerializeLocalization(ev.Latitude, ev.Longitude, ev.Altitude);
                foreach (var loc in ev.GetLocalisations(login))
                {
                    db.Insert(loc);

                    if (!string.IsNullOrWhiteSpace(geoString))
                    {
                        db.Execute("UPDATE [dbo].[CollectionEventLocalisation] SET geography=GEOGRAPHY::STGeomFromText(@0, 4326) WHERE CollectionEventID=@1 AND LocalisationSystemID=@2", geoString, loc.CollectionEventID, loc.LocalisationSystemID);
                    }
                }

                if (properties != null)
                    foreach (var p in properties)
                    {
                        p.CollectionEventID = ev.CollectionEventID;
                        db.Insert(p);
                    }

                t.Complete();

                return ev.CollectionEventID;
            }
        }
 public IEnumerable<Event> EventsByLocality(string locality, UserCredentials login)
 {
     using (var db = login.GetConnection())
     {
         return db.Query<Event>("FROM [dbo].[DiversityMobile_EventsForProject] (@0, @1) as [CollectionEvent]", login.ProjectID, locality).Take(15).ToList();
     }
 }
        public int InsertIdentificationUnit(IdentificationUnit iu, IEnumerable<IdentificationUnitAnalysis> analyses, UserCredentials login)
        {
            using (var db = login.GetConnection())
            using (var t = db.GetTransaction())
            {
                db.Insert(iu);
                db.Insert(iu.GetIdentification(login));

                db.Insert(iu.GetGeoAnalysis(login));

                var geoString = SerializeLocalization(iu.Latitude, iu.Longitude, iu.Altitude);
                if (!string.IsNullOrWhiteSpace(geoString))
                {
                    db.Execute("UPDATE [dbo].[IdentificationUnitGeoAnalysis] SET Geography=GEOGRAPHY::STGeomFromText(@0, 4326) WHERE CollectionSpecimenID=@1 AND IdentificationUnitID=@2", geoString, iu.CollectionSpecimenID, iu.CollectionUnitID);
                }

                if (analyses != null)
                    foreach (var a in analyses)
                    {
                        a.CollectionUnitID = iu.CollectionUnitID;
                        a.CollectionSpecimenID = iu.CollectionSpecimenID;
                        db.Insert(a);
                    }

                t.Complete();

                return iu.CollectionUnitID;
            }
        }
 public IEnumerable<Model.AnalysisResult> GetAnalysisResultsForProject(int projectID, UserCredentials login)
 {
     using (var db = login.GetConnection())
     {
         return analysisResultsForProject(projectID, db).ToList();
     }
 }
 public IEnumerable<Model.Analysis> GetAnalysesForProject(int projectID, UserCredentials login)
 {
     using (var db = login.GetConnection())
     {
         var res = analysesForProject(projectID, db).ToList();
         return res;
     }
 }
        public IEnumerable<IdentificationUnitAnalysis> AnalysesForIU(int collectionUnitID, UserCredentials login)
        {
            using (var db = login.GetConnection())
            {
                var analyses = db.Query<IdentificationUnitAnalysis>("WHERE IdentificationUnitID=@0", collectionUnitID).ToList();

                return analyses;
            }
        }
 public IEnumerable<Model.PropertyValue> DownloadPropertyNames(Property p, int page, UserCredentials login)
 {
     var propsForUser = propertyListsForUser(login).ToDictionary(pl => pl.PropertyID);
     PropertyList list;
     if (propsForUser.TryGetValue(p.PropertyID, out list))
     {
         return loadTablePaged<Model.PropertyValue>(list.Table, page, login.GetConnection(CATALOG_DIVERSITYMOBILE));
     }
     else
         return Enumerable.Empty<Model.PropertyValue>();
 }
        public IEnumerable<TaxonName> DownloadTaxonList(TaxonList list, int page, UserCredentials login)
        {
            Diversity db;
            if (list.IsPublicList)
            {
                var taxa = ServiceConfiguration.PublicTaxa;
                db = new Diversity(taxa.Login, taxa.Server, taxa.Catalog);
            }
            else
                db = login.GetConnection(CATALOG_DIVERSITYMOBILE);

            return loadTablePaged<Model.TaxonName>(list.Table, page, db);
        }
        public IEnumerable<IdentificationUnit> UnitsForSpecimen(int collectionSpecimenID, UserCredentials login)
        {
            using (var db = login.GetConnection())
            {
                var ius = db.Query<IdentificationUnit>("WHERE CollectionSpecimenID=@0", collectionSpecimenID).ToList();

                foreach (var iu in ius)
                {
                    AddUnitExternalInformation(iu, db);
                }
                return ius;
            }
        }
        public IEnumerable<Event> EventsByLocality(string locality, UserCredentials login)
        {
            using (var db = login.GetConnection())
            {
                var events = db.Query<Event>("FROM [dbo].[DiversityMobile_EventsForProject] (@0, @1) as [CollectionEvent]", login.ProjectID, locality).Take(50).ToList();

                foreach (var ev in events)
                {
                    AddLocalization(ev, db);
                }

                return events;
            }
        }
        public int InsertSpecimen(Specimen s, UserCredentials login)
        {
            using (var db = login.GetConnection())
            using (var t = new Transaction(db))
            {
                db.Insert(s);

                db.Insert(s.GetProject(login.ProjectID));
                db.Insert(s.GetAgent(login));

                t.Complete();
                return s.CollectionSpecimenID;
            }
        }
        public int InsertEventSeries(EventSeries series, IEnumerable<Localization> localizations, UserCredentials login)
        {
            using (var db = login.GetConnection())
            using (var t = new Transaction(db))
            {
                db.Insert(series);

                var geoString = SerializeLocalizations(localizations);
                if (!string.IsNullOrWhiteSpace(geoString))
                    db.Execute("Update [dbo].[CollectionEventSeries] Set geography=@0 Where SeriesID=@1", geoString, series.CollectionEventSeriesID);

                t.Complete();
                return series.CollectionEventSeriesID;
            }
        }
        public int InsertEventSeries(EventSeries series, IEnumerable<Localization> localizations, UserCredentials login)
        {
            using (var db = login.GetConnection())
            using (var t = new Transaction(db))
            {
                db.Insert(series);

                var geoString = SerializeLocalizations(localizations);
                if (!string.IsNullOrWhiteSpace(geoString))
                    db.Execute("UPDATE [dbo].[CollectionEventSeries] SET geography=GEOGRAPHY::STGeomFromText(@0, 4326) WHERE SeriesID=@1", geoString, series.CollectionEventSeriesID);

                t.Complete();
                return series.CollectionEventSeriesID;
            }
        }
        public IEnumerable<Term> GetStandardVocabulary(UserCredentials login)
        {

            IEnumerable<Term> linqTerms;
            using (var db = login.GetConnection())         
            {
                linqTerms =
                Enumerable.Concat(
                    db.Query<Term>("FROM [dbo].[DiversityMobile_TaxonomicGroups]() as Term")
                    .Select(t => { t.Source = DiversityPhone.Model.TermList.TaxonomicGroups; return t; }),
                    db.Query<Term>("FROM [dbo].[DiversityMobile_UnitRelationTypes]() as Term")
                    .Select(t => { t.Source = DiversityPhone.Model.TermList.RelationshipTypes; return t; })
                    ).ToList();
            }
            return linqTerms;

        }
 public IEnumerable<Project> GetProjectsForUser(UserCredentials login)
 {  
     if(string.IsNullOrWhiteSpace(login.Repository))
         return Enumerable.Empty<Project>();
     using (var db = login.GetConnection())
     {
         try
         {
             return db.Query<Project>("FROM [dbo].[DiversityMobile_ProjectList] () AS [Project]")
                 .Select(p =>
                     {
                         p.DisplayText = p.DisplayText ?? "No Description";
                         return p;
                     })
                 .ToList(); //TODO Use credential DB
         }
         catch
         {
             return Enumerable.Empty<Project>();
         }
     }            
 }
        public IObservable<Unit> Start(
            UserCredentials login
            )
        {
            lock (this)
            {
                if (!_HasStarted)
                {

                    _Credentials = login;

                    if (_Credentials != null)
                    {
                        Notification.showProgress(_Progress);
                        var execution =
                        Observable.Concat(
                            clearVocabulary(),
                            loadVocabulary(),
                            loadAnalyses(),
                            loadResults(),
                            loadQualifications(),
                            loadProperties())
                            .Finally(() => { if (_Progress != null) _Progress.OnCompleted(); })
                            .Replay();

                        _Execute = execution;

                        execution.Connect();
                    }
                    else
                        throw new ArgumentException("login");
                }

                _HasStarted = true;

                return _Execute;
            }            
        }
        public int InsertIdentificationUnit(IdentificationUnit iu, IEnumerable<IdentificationUnitAnalysis> analyses, UserCredentials login)
        {
            using (var db = login.GetConnection())
            using (var t = db.GetTransaction())
            {

                db.Insert(iu);
                db.Insert(iu.GetIdentification(login));
                db.Insert(iu.GetGeoAnalysis(login));

                if (analyses != null)
                    foreach (var a in analyses)
                    {
                        a.CollectionUnitID = iu.CollectionUnitID;
                        a.CollectionSpecimenID = iu.CollectionSpecimenID;
                        db.Insert(a);
                    }

                t.Complete();

                return iu.CollectionUnitID;
            }
        }
        public DiversityServiceClient(ICredentialsService Credentials, IKeyMappingService Mapping)
        {            
            this.Mapping = Mapping;
            this.Credentials = Credentials;

            Credentials.CurrentCredentials().Where(c => c != null).Subscribe(c => _CurrentCredentials = c);

            GetUserInfoCompleted = Observable.FromEventPattern<GetUserInfoCompletedEventArgs>(h => _svc.GetUserInfoCompleted += h, h => _svc.GetUserInfoCompleted -= h);
            GetRepositoriesCompleted = Observable.FromEventPattern<GetRepositoriesCompletedEventArgs>(h => _svc.GetRepositoriesCompleted += h, h => _svc.GetRepositoriesCompleted -= h);
            GetPropertiesForUserCompleted = Observable.FromEventPattern<GetPropertiesForUserCompletedEventArgs>(h => _svc.GetPropertiesForUserCompleted += h, h => _svc.GetPropertiesForUserCompleted -= h);
            GetProjectsForUserCompleted = Observable.FromEventPattern<GetProjectsForUserCompletedEventArgs>(h => _svc.GetProjectsForUserCompleted += h, h => _svc.GetProjectsForUserCompleted -= h);
            GetStandardVocabularyCompleted = Observable.FromEventPattern<GetStandardVocabularyCompletedEventArgs>(d => _svc.GetStandardVocabularyCompleted += d, d => _svc.GetStandardVocabularyCompleted -= d);
            GetAnalysesForProjectCompleted = Observable.FromEventPattern<GetAnalysesForProjectCompletedEventArgs>(d => _svc.GetAnalysesForProjectCompleted += d, d => _svc.GetAnalysesForProjectCompleted -= d);
            GetAnalysisResultsForProjectCompleted = Observable.FromEventPattern<GetAnalysisResultsForProjectCompletedEventArgs>( d => _svc.GetAnalysisResultsForProjectCompleted += d, d => _svc.GetAnalysisResultsForProjectCompleted -= d);
            GetAnalysisTaxonomicGroupsForProjectCompleted = Observable.FromEventPattern<GetAnalysisTaxonomicGroupsForProjectCompletedEventArgs>(d => _svc.GetAnalysisTaxonomicGroupsForProjectCompleted += d, d => _svc.GetAnalysisTaxonomicGroupsForProjectCompleted -= d);

            GetTaxonListsForUser = Observable.FromEventPattern<GetTaxonListsForUserCompletedEventArgs>( d => _svc.GetTaxonListsForUserCompleted += d, d => _svc.GetTaxonListsForUserCompleted -= d);
            DownloadTaxonList = Observable.FromEventPattern<DownloadTaxonListCompletedEventArgs>( d => _svc.DownloadTaxonListCompleted += d, d => _svc.DownloadTaxonListCompleted -= d);
            GetQualificationsCompleted = Observable.FromEventPattern<GetQualificationsCompletedEventArgs>( d => _svc.GetQualificationsCompleted += d, d => _svc.GetQualificationsCompleted -= d);

            InsertMMOCompleted = Observable.FromEventPattern<AsyncCompletedEventArgs>(h => _svc.InsertMMOCompleted += h, h => _svc.InsertMMOCompleted -= h);
            InsertESCompleted = Observable.FromEventPattern<InsertEventSeriesCompletedEventArgs>(h => _svc.InsertEventSeriesCompleted += h, h => _svc.InsertEventSeriesCompleted -= h);
            InsertEVCompleted = Observable.FromEventPattern<InsertEventCompletedEventArgs>(h => _svc.InsertEventCompleted += h, h => _svc.InsertEventCompleted -= h);
            InsertSPCompleted = Observable.FromEventPattern<InsertSpecimenCompletedEventArgs>(h => _svc.InsertSpecimenCompleted += h, h => _svc.InsertSpecimenCompleted -= h);
            InsertIUCompleted = Observable.FromEventPattern<InsertIdentificationUnitCompletedEventArgs>(h => _svc.InsertIdentificationUnitCompleted += h, h => _svc.InsertIdentificationUnitCompleted -= h);

            UploadMultimediaCompleted = Observable.FromEventPattern<SubmitCompletedEventArgs>(h => _multimedia.SubmitCompleted += h, h => _multimedia.SubmitCompleted -= h);

            EventSeriesByIDCompleted = Observable.FromEventPattern<EventSeriesByIDCompletedEventArgs>(h => _svc.EventSeriesByIDCompleted += h, h => _svc.EventSeriesByIDCompleted -= h);
            LocalizationsForSeriesCompleted = Observable.FromEventPattern<LocalizationsForSeriesCompletedEventArgs>(h => _svc.LocalizationsForSeriesCompleted += h, h => _svc.LocalizationsForSeriesCompleted -= h);
            EventsByLocalityCompleted = Observable.FromEventPattern<EventsByLocalityCompletedEventArgs>(h => _svc.EventsByLocalityCompleted += h, h => _svc.EventsByLocalityCompleted -= h);
            PropertiesForEventCompleted = Observable.FromEventPattern<PropertiesForEventCompletedEventArgs>(h => _svc.PropertiesForEventCompleted += h, h => _svc.PropertiesForEventCompleted -= h);
            SpecimenForEventCompleted = Observable.FromEventPattern<SpecimenForEventCompletedEventArgs>(h => _svc.SpecimenForEventCompleted += h, h => _svc.SpecimenForEventCompleted -= h);
            UnitsForSpecimenCompleted = Observable.FromEventPattern<UnitsForSpecimenCompletedEventArgs>(h => _svc.UnitsForSpecimenCompleted += h, h => _svc.UnitsForSpecimenCompleted -= h);
            SubUnitsForIUCompleted = Observable.FromEventPattern<SubUnitsForIUCompletedEventArgs>(h => _svc.SubUnitsForIUCompleted += h, h => _svc.SubUnitsForIUCompleted -= h);
            AnalysesForIUCompleted = Observable.FromEventPattern<AnalysesForIUCompletedEventArgs>(h => _svc.AnalysesForIUCompleted += h, h => _svc.AnalysesForIUCompleted -= h);
        }
        public void InsertMMO(MultimediaObject mmo, UserCredentials login)
        {
            using (var db = login.GetConnection())
            {
                try
                {
                    switch (mmo.OwnerType)
                    {
                        case MultimediaOwner.EventSeries:
                            CollectionEventSeriesImage cesi = mmo.ToSeriesImage();
                            db.Insert(cesi);
                            break;

                        case MultimediaOwner.Event:
                            CollectionEventImage cei = mmo.ToEventImage();
                            db.Insert(cei);
                            break;

                        case MultimediaOwner.Specimen:
                        case MultimediaOwner.IdentificationUnit:
                            CollectionSpecimenImage csi = mmo.ToSpecimenImage(db);
                            db.Insert(csi);
                            break;

                        default:
                            throw new ArgumentException("unknown type");
                    }
                }
                catch (SqlException)
                {
                    // Presumably Multiple Insert, meaning the object already exists
                    // -> Success
                }
            }
        }
 public IEnumerable<Localization> LocalizationsForSeries(int collectionSeriesID, UserCredentials login)
 {
     //Maybe via functions?
     return Enumerable.Empty<Localization>();
 }
        public IEnumerable<Repository> GetRepositories(UserCredentials login)
        {           

            List<Repository> result = new List<Repository>();

            Parallel.ForEach(Configuration.ServiceConfiguration.Repositories, repo =>
            {
                using (var ctx = new Diversity(login, repo.Server, repo.Catalog))
                {
                    try
                    {
                        ctx.OpenSharedConnection(); // validate Credentials
                        lock (result)
                        {
                            result.Add(new Repository() { Database = repo.Catalog, DisplayText = repo.name });
                        }
                    }
                    catch (Exception)
                    {
                    }
                }
            });

            return result;
        }
 public IEnumerable<Qualification> GetQualifications(UserCredentials login)
 {
     using (var db = login.GetConnection())
     {
         return getQualifications(db)
             .Select(q => 
                 {
                     if(string.IsNullOrWhiteSpace(q.DisplayText))
                     {
                         q.DisplayText = "no qualifier";
                     }
                     return q;
                 })
             .ToList();
     }
 }
 public IEnumerable<Model.Property> GetPropertiesForUser(UserCredentials login)
 {
     var propsForUser = propertyListsForUser(login).ToDictionary(pl => pl.PropertyID);
     
     using (var db = login.GetConnection())
     {
         return getProperties(db).Where(p => propsForUser.ContainsKey(p.PropertyID)).ToList();
     }            
 }
 public IEnumerable<Model.TaxonList> GetTaxonListsForUser(UserCredentials login)
 {
     List<Model.TaxonList> result = new List<TaxonList>();
     using (var db = login.GetConnection(CATALOG_DIVERSITYMOBILE))
     {
         result.AddRange(
             taxonListsForUser(login.LoginName,db)
             .Select(l => {l.IsPublicList = false; return l;})
             );
     }
     var publicTaxa = ServiceConfiguration.PublicTaxa;
     using (var db = new DiversityORM.Diversity(publicTaxa.Login, publicTaxa.Server, publicTaxa.Catalog))
     {
         result.AddRange(
             taxonListsForUser(db)
             .Select(l => { l.IsPublicList = true; return l; })
             );
     }
     return result;
 }
        public UserProfile GetUserInfo(UserCredentials login)
        {
            try
            {
                using (var db = login.GetConnection())
                {
                    return db.Query<UserProfile>("FROM [DiversityMobile_UserInfo]() AS [UserProfile]").Single();
                }
            }
            catch
            {
                return null;
            }

        }