public void DequeueRecipe(AuthorIdentity identity, params Guid[] recipeIds)
        {
            using (var session = this.GetSession())
            {
                var recipes = (from recipe in recipeIds select new Recipes { RecipeId = recipe }).ToArray();

                var databaseRecipes = session.QueryOver<QueuedRecipes>().Where(p => p.UserId == identity.UserId);

                if (recipeIds.Any())
                {
                    databaseRecipes = databaseRecipes.AndRestrictionOn(p => p.Recipe).IsInG(recipes);
                }

                using (var transaction = session.BeginTransaction())
                {
                    databaseRecipes.List().ForEach(session.Delete);
                    transaction.Commit();
                }
            }
        }
        public SearchResults Search(AuthorIdentity identity, RecipeQuery query)
        {
            var index = this.store.GetSearchIndex();

             var q = index.Where(p => !p.Recipe.Hidden);

             if (!string.IsNullOrWhiteSpace(query.Keywords))
             {
            q = q.Where(p =>
               (p.Recipe.Title ?? string.Empty).IndexOf(query.Keywords, StringComparison.OrdinalIgnoreCase) >= 0 ||
               (p.Recipe.Description ?? string.Empty).IndexOf(query.Keywords, StringComparison.OrdinalIgnoreCase) >= 0);
             }

             if (query.Time.MaxPrep.HasValue)
             {
            q = q.Where(p => p.Recipe.PrepTime <= query.Time.MaxPrep.Value);
             }

             if (query.Time.MaxCook.HasValue)
             {
            q = q.Where(p => p.Recipe.CookTime <= query.Time.MaxCook.Value);
             }

             if (query.Rating > 0)
             {
            q = q.Where(p => p.Recipe.Rating >= (int)query.Rating.Value);
             }

             if (query.Include != null && query.Include.Length > 0)
             {
             // Add ingredients to include
            q = q.Where(p => p.Ingredients.Any(i => query.Include.Contains(i.IngredientId)));
             }

             if (query.Exclude != null && query.Exclude.Length > 0)
             {
             // Add ingredients to exclude
            q = q.Where(p => !p.Ingredients.Any(i => query.Exclude.Contains(i.IngredientId)));
             }

             if (query.Photos == PhotoFilter.Photo || query.Photos == PhotoFilter.HighRes)
             {
            q = q.Where(p => p.Recipe.ImageUrl != null);
             }

             if (query.Diet || query.Nutrition || query.Skill || query.Taste || (query.Meal != MealFilter.All) || (query.Photos == PhotoFilter.HighRes))
             {
            // Meal
            if (query.Meal != MealFilter.All)
            {
                if (query.Meal == MealFilter.Breakfast)
                {
                    q = q.Where(p => p.Metadata.MealBreakfast);
                }

                if (query.Meal == MealFilter.Dessert)
                {
                    q = q.Where(p => p.Metadata.MealDessert);
                }

                if (query.Meal == MealFilter.Dinner)
                {
                    q = q.Where(p => p.Metadata.MealDinner);
                }

                if (query.Meal == MealFilter.Lunch)
                {
                    q = q.Where(p => p.Metadata.MealLunch);
                }
            }

             // High-res photos
             if (query.Photos == PhotoFilter.HighRes)
             {
                 q = q.Where(p => p.Metadata.PhotoRes >= 1024 * 768);
             }

             // Diet
             if (query.Diet.GlutenFree)
             {
                 q = q.Where(p => p.Metadata.DietGlutenFree);
             }

             if (query.Diet.NoAnimals)
             {
                 q = q.Where(p => p.Metadata.DietNoAnimals);
             }

             if (query.Diet.NoMeat)
             {
                 q = q.Where(p => p.Metadata.DietNomeat);
             }

             if (query.Diet.NoPork)
             {
                 q = q.Where(p => p.Metadata.DietNoPork);
             }

             if (query.Diet.NoRedMeat)
             {
                 q = q.Where(p => p.Metadata.DietNoRedMeat);
             }

             // Nutrition
             if (query.Nutrition.LowCalorie)
             {
                 q = q.Where(p => p.Metadata.NutritionLowCalorie);
             }

             if (query.Nutrition.LowCarb)
             {
                 q = q.Where(p => p.Metadata.NutritionLowCarb);
             }

             if (query.Nutrition.LowFat)
             {
                 q = q.Where(p => p.Metadata.NutritionLowFat);
             }

             if (query.Nutrition.LowSodium)
             {
                 q = q.Where(p => p.Metadata.NutritionLowSodium);
             }

             if (query.Nutrition.LowSugar)
             {
                 q = q.Where(p => p.Metadata.NutritionLowSugar);
             }

             // Skill
             if (query.Skill.Common)
             {
                 q = q.Where(p => p.Metadata.SkillCommon).OrderByDescending(p => p.Metadata.Commonality);
             }

             if (query.Skill.Easy)
             {
                 q = q.Where(p => p.Metadata.SkillEasy);
             }

             if (query.Skill.Quick)
             {
                 q = q.Where(p => p.Metadata.SkillQuick);
             }

             // Taste
            if (query.Taste.MildToSpicy != SpicinessLevel.Medium)
            {
               q = query.Taste.MildToSpicy < SpicinessLevel.Medium
                  ? q.Where(p => p.Metadata.TasteMildToSpicy <= query.Taste.Spiciness).OrderBy(p => p.Metadata.TasteMildToSpicy)
                  : q.Where(p => p.Metadata.TasteMildToSpicy >= query.Taste.Spiciness).OrderByDescending(p => p.Metadata.TasteMildToSpicy);
            }

            if (query.Taste.SavoryToSweet != SweetnessLevel.Medium)
            {
               q = query.Taste.SavoryToSweet < SweetnessLevel.Medium
                  ? q.Where(p => p.Metadata.TasteSavoryToSweet <= query.Taste.Sweetness).OrderBy(p => p.Metadata.TasteSavoryToSweet)
                  : q.Where(p => p.Metadata.TasteSavoryToSweet >= query.Taste.Sweetness).OrderByDescending(p => p.Metadata.TasteSavoryToSweet);
            }
             }

             switch (query.Sort)
             {
            case SortOrder.Title:
               q = (query.Direction == SortDirection.Ascending) ? q.OrderBy(p => p.Recipe.Title) : q.OrderByDescending(p => p.Recipe.Title);
               break;
            case SortOrder.PrepTime:
               q = (query.Direction == SortDirection.Ascending) ? q.OrderBy(p => p.Recipe.PrepTime) : q.OrderByDescending(p => p.Recipe.PrepTime);
               break;
            case SortOrder.CookTime:
               q = (query.Direction == SortDirection.Ascending) ? q.OrderBy(p => p.Recipe.CookTime) : q.OrderByDescending(p => p.Recipe.CookTime);
               break;
            case SortOrder.Image:
               q = (query.Direction == SortDirection.Ascending) ? q.OrderBy(p => p.Recipe.ImageUrl) : q.OrderByDescending(p => p.Recipe.ImageUrl);
               break;
            default:
               q = (query.Direction == SortDirection.Ascending) ? q.OrderBy(p => p.Recipe.Rating) : q.OrderByDescending(p => p.Recipe.Rating);
               break;
             }

             return new SearchResults
             {
            Briefs = q.Select(r => Provisioning.DTO.Recipes.ToRecipeBrief(r.Recipe)).ToArray(),
            TotalCount = q.Count()
             };
        }
        public void DeleteShoppingLists(AuthorIdentity identity, ShoppingList[] lists)
        {
            if (!lists.Any())
            {
                throw new ArgumentException("DeleteShoppingLists requires at least one list to delete.");
            }

            using (var session = this.GetSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    var databaseLists =
                        session.QueryOver<ShoppingLists>()
                            .AndRestrictionOn(p => p.ShoppingListId)
                            .IsInG(lists.Where(l => l.Id.HasValue).Select(l => l.Id.Value))
                            .Where(p => p.UserId == identity.UserId)
                            .List();

                    databaseLists.ForEach(session.Delete);
                    transaction.Commit();
                }
            }
        }
        public Recipe[] ReadRecipes(AuthorIdentity identity, Guid[] recipeIds, ReadRecipeOptions options)
        {
            using (var session = this.GetSession())
            {
                var databaseRecipes =
                    session.QueryOver<Recipes>()
                        .Fetch(prop => prop.RecipeMetadata)
                        .Eager.Fetch(prop => prop.Ingredients)
                        .Eager.Fetch(prop => prop.Ingredients[0].Ingredient)
                        .Eager.Fetch(prop => prop.Ingredients[0].IngredientForm)
                        .Eager.AndRestrictionOn(p => p.RecipeId)
                        .IsInG(recipeIds)
                        .TransformUsing(Transformers.DistinctRootEntity)
                        .List();

                if (!databaseRecipes.Any())
                {
                    throw new RecipeNotFoundException();
                }

                var recipes = new List<Recipe>();
                foreach (var databaseRecipe in databaseRecipes)
                {
                    var recipe = new Recipe
                                     {
                                         Id = databaseRecipe.RecipeId,
                                         Title = databaseRecipe.Title,
                                         Description = databaseRecipe.Description,
                                         DateEntered = databaseRecipe.DateEntered,
                                         ImageUrl = databaseRecipe.ImageUrl,
                                         ServingSize = databaseRecipe.ServingSize,
                                         PreparationTime = databaseRecipe.PrepTime,
                                         CookingTime = databaseRecipe.CookTime,
                                         Credit = databaseRecipe.Credit,
                                         CreditUrl = databaseRecipe.CreditUrl,
                                         AverageRating = databaseRecipe.Rating
                                     };

                    if (options.ReturnMethod)
                    {
                        recipe.Method = databaseRecipe.Steps;
                    }

                    if (options.ReturnUserRating)
                    {
                        // TODO: We should JOIN this on the databaseRecipes for faster loading
                        var id = databaseRecipe.RecipeId;
                        var rating =
                            session.QueryOver<RecipeRatings>()
                                .Where(p => p.Recipe.RecipeId == id)
                                .Where(p => p.UserId == identity.UserId)
                                .SingleOrDefault();

                        recipe.UserRating = rating == null ? Rating.None : (Rating)rating.Rating;
                    }

                    recipe.Ingredients =
                        databaseRecipe.Ingredients.Select(
                            i =>
                            new IngredientUsage
                                {
                                    Amount = i.Qty.HasValue ? new Amount(i.Qty.Value, i.Unit) : null,
                                    PrepNote = i.PrepNote,
                                    Section = i.Section,
                                    Form =
                                        i.IngredientForm != null
                                            ? i.IngredientForm.AsIngredientForm()
                                            : null,

                                    // Note: Form will be null when usage has no amount
                                    Ingredient = i.Ingredient.AsIngredient()
                                }).ToArray();

                    recipe.Tags = databaseRecipe.RecipeMetadata.Tags;
                    recipes.Add(recipe);
                }

                return recipes.ToArray();
            }
        }
        public MenuResult UpdateMenu(
            AuthorIdentity identity, 
            Guid? menuId, 
            Guid[] recipesAdd, 
            Guid[] recipesRemove, 
            MenuMove[] recipesMove, 
            bool clear, 
            string newName = null)
        {
            var menu = new MenuResult();

            using (var session = this.GetSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    Menus databaseMenu = null;
                    IList<Favorites> databaseRecipes = null;
                    if (menuId.HasValue)
                    {
                        databaseMenu =
                            session.QueryOver<Menus>()
                                .Fetch(prop => prop.Recipes)
                                .Eager.Where(p => p.MenuId == menuId)
                                .SingleOrDefault();

                        if (databaseMenu == null)
                        {
                            throw new MenuNotFoundException();
                        }

                        CheckForUserAccess(identity, databaseMenu);

                        RenameMenu(newName, databaseMenu);

                        databaseRecipes = databaseMenu.Recipes;
                    }
                    else
                    {
                        databaseRecipes =
                            session.QueryOver<Favorites>()
                                .Where(p => p.UserId == identity.UserId)
                                .Where(p => p.Menu == null)
                                .List();
                    }

                    if (recipesAdd.Any())
                    {
                        AddRecipesToMenu(identity, recipesAdd, databaseRecipes, databaseMenu, session);
                        menu.MenuUpdated = true;
                    }

                    if (recipesRemove.Any())
                    {
                        RemoveRecipesFromMenu(recipesRemove, databaseRecipes, session);
                        menu.MenuUpdated = true;
                    }

                    if (clear)
                    {
                        RemoveAllRecipesFromMenu(databaseRecipes, session);
                        menu.MenuUpdated = true;
                    }

                    if (recipesMove.Any())
                    {
                        MoveRecipesToAnotherMenu(identity, recipesMove, session, databaseRecipes);
                        menu.MenuUpdated = true;
                    }

                    transaction.Commit();
                }
            }

            return menu;
        }
        public RecipeBrief[] GetRecipeQueue(AuthorIdentity identity)
        {
            using (var session = this.GetSession())
            {
                var databaseRecipes =
                    session.QueryOver<QueuedRecipes>()
                        .Fetch(prop => prop.Recipe)
                        .Eager.Where(p => p.UserId == identity.UserId)
                        .List();

                return (from recipe in databaseRecipes select recipe.Recipe.AsRecipeBrief()).ToArray();
            }
        }
        public void MoveMenuItem(AuthorIdentity identity, Guid recipeId, Menu fromMenu, Menu toMenu)
        {
            using (var session = this.GetSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    if (!fromMenu.Id.HasValue || !toMenu.Id.HasValue)
                    {
                        throw new MenuIdRequiredException();
                    }

                    var favorite =
                        session.QueryOver<Favorites>()
                            .Where(p => p.Menu.MenuId == fromMenu.Id.Value)
                            .Where(p => p.Recipe.RecipeId == recipeId)
                            .SingleOrDefault();

                    if (favorite == null)
                    {
                        throw new RecipeNotFoundException();
                    }

                    var databaseToMenu = session.QueryOver<Menus>().Where(p => p.MenuId == toMenu.Id.Value).SingleOrDefault();

                    if (databaseToMenu == null)
                    {
                        throw new MenuNotFoundException();
                    }

                    favorite.Menu = databaseToMenu;
                    session.Update(favorite);
                    transaction.Commit();
                }
            }
        }
        private static void DeleteItems(AuthorIdentity identity, Guid? listId, Guid[] toRemove, ISession session)
        {
            var deletes =
                session.QueryOver<ShoppingListItems>()
                    .Where(p => p.UserId == identity.UserId)
                    .Where(
                        listId.HasValue
                            ? Restrictions.Eq("ShoppingList", listId.Value)
                            : Restrictions.IsNull("ShoppingList"))
                    .AndRestrictionOn(p => p.ItemId)
                    .IsInG(toRemove)
                    .List();

            deletes.ForEach(session.Delete);
        }
        private static IList<ShoppingListItems> LoadItemsIntoLists(
            AuthorIdentity identity, 
            bool defaultsLoaded, 
            IList<ShoppingLists> databaseLists, 
            ISession session)
        {
            ICriterion filter = defaultsLoaded
                                    ? Restrictions.Or(
                                        Restrictions.IsNull("ShoppingList"),
                                        Restrictions.InG("ShoppingList", databaseLists))

                                    // Menu can be null, or in loaded menu list
                                    : Restrictions.InG("ShoppingList", databaseLists); // Menu must be in loaded menu list

            var databaseItems =
                session.QueryOver<ShoppingListItems>()
                    .Fetch(prop => prop.Ingredient)
                    .Eager.Fetch(prop => prop.Recipe)
                    .Eager.Where(p => p.UserId == identity.UserId)
                    .Where(filter)
                    .List();
            return databaseItems;
        }
 private static void CheckForUserAccess(AuthorIdentity identity, Menus databaseMenu)
 {
     if (databaseMenu.UserId != identity.UserId)
     {
         throw new UserDoesNotOwnMenuException();
     }
 }
        private static List<Guid> CheckingForRecipeDuplicates(AuthorIdentity identity, Guid[] recipeIds, ISession session)
        {
            var recipes = (from r in recipeIds select new Recipes { RecipeId = r }).ToArray();

            var dupes =
                session.QueryOver<QueuedRecipes>()
                    .Where(p => p.UserId == identity.UserId)
                    .AndRestrictionOn(p => p.Recipe)
                    .IsInG(recipes)
                    .List<QueuedRecipes>();

            var existing = (from r in dupes select r.Recipe.RecipeId).ToList();
            return existing;
        }
        public MenuResult CreateMenu(AuthorIdentity identity, Menu menu, params Guid[] recipeIds)
        {
            using (var session = this.GetSession())
            {
                menu.Title = menu.Title.Trim();
                var newMenu = new MenuResult();

                using (var transaction = session.BeginTransaction())
                {
                    Menus databaseMenu;
                    var duplicates =
                        session.QueryOver<Menus>()
                            .Where(p => p.UserId == identity.UserId)
                            .Where(p => p.Title == menu.Title)
                            .ToRowCountQuery()
                            .RowCount();

                    if (duplicates > 0)
                    {
                        throw new MenuAlreadyExistsException();
                    }

                    session.Save(
                        databaseMenu = new Menus { UserId = identity.UserId, Title = menu.Title, CreatedDate = DateTime.Now });

                    foreach (var recipeId in recipeIds.NeverNull())
                    {
                        var fav = new Favorites
                                      {
                                          UserId = identity.UserId,
                                          Recipe = new Recipes { RecipeId = recipeId },
                                          Menu = databaseMenu
                                      };

                        session.Save(fav);
                    }

                    transaction.Commit();

                    newMenu.MenuCreated = true;
                    newMenu.NewMenuId = databaseMenu.MenuId;
                }

                return newMenu;
            }
        }
        private static ShoppingListResult AddShopingListItems(
            AuthorIdentity identity, 
            IShoppingListSource[] toAdd, 
            IList<ShoppingListItems> databaseItems, 
            ShoppingLists databaseList, 
            ISession session, 
            ITransaction transaction)
        {
            toAdd.ForEach(
                item =>
                    {
                        var source = item.GetItem();

                        if (source.Ingredient == null && !string.IsNullOrWhiteSpace(source.Raw))
                        {
                            // Raw shopping list item
                            if (!databaseItems.Any(i => source.Raw.Equals(i.Raw, StringComparison.OrdinalIgnoreCase)))
                            {
                                // Add it
                                var newItem = new ShoppingListItems
                                                  {
                                                      ShoppingList = databaseList,
                                                      UserId = identity.UserId,
                                                      Raw = source.Raw
                                                  };

                                session.Save(newItem);
                                databaseItems.Add(newItem);
                            }

                            return;
                        }

                        if (source.Ingredient != null && source.Amount == null)
                        {
                            // Raw ingredient without any amount
                            var existingItem =
                                databaseItems.FirstOrDefault(
                                    i => i.Ingredient != null && i.Ingredient.IngredientId == source.Ingredient.Id);

                            if (existingItem == null)
                            {
                                // Add it
                                var newItem = new ShoppingListItems
                                                  {
                                                      ShoppingList = databaseList,
                                                      UserId = identity.UserId,
                                                      Ingredient =
                                                          Ingredients.FromId(source.Ingredient.Id)
                                                  };

                                session.Save(newItem);
                                databaseItems.Add(newItem);
                            }
                            else
                            {
                                // Clear out existing amount
                                existingItem.Amount = null;
                            }
                        }

                        if (source.Ingredient != null && source.Amount != null)
                        {
                            // Ingredient with amount, aggregate if necessary
                            var existingItem =
                                databaseItems.FirstOrDefault(
                                    i => i.Ingredient != null && i.Ingredient.IngredientId == source.Ingredient.Id);

                            if (existingItem == null)
                            {
                                // Add it
                                var newItem = new ShoppingListItems
                                                  {
                                                      ShoppingList = databaseList,
                                                      UserId = identity.UserId,
                                                      Ingredient =
                                                          Ingredients.FromId(source.Ingredient.Id),
                                                      Amount = source.Amount
                                                  };

                                session.Save(newItem);
                                databaseItems.Add(newItem);
                            }
                            else if (existingItem.Amount != null)
                            {
                                // Add to total
                                existingItem.Amount += source.Amount;
                            }
                        }
                    });

            transaction.Commit();

            return new ShoppingListResult
                       {
                           List =
                               new ShoppingList(
                               databaseList != null ? (Guid?)databaseList.ShoppingListId : null,
                               databaseList != null ? databaseList.Title : null,
                               databaseItems.Select(i => i.AsShoppingListItem()))
                       };
        }
        private static void AddRecipesToMenu(
            AuthorIdentity identity, 
            Guid[] recipesAdd, 
            IList<Favorites> databaseRecipes, 
            Menus databaseMenu, 
            ISession session)
        {
            var existing = from r in databaseRecipes select r.Recipe.RecipeId;
            recipesAdd = recipesAdd.Except(existing).ToArray(); // Remove duplicates

            foreach (var recipeId in recipesAdd)
            {
                var fav = new Favorites
                              {
                                  UserId = identity.UserId,
                                  Recipe = new Recipes { RecipeId = recipeId },
                                  Menu = databaseMenu
                              };

                session.Save(fav);
            }
        }
        public void EnqueueRecipes(AuthorIdentity identity, params Guid[] recipeIds)
        {
            using (var session = this.GetSession())
            {
                var existing = CheckingForRecipeDuplicates(identity, recipeIds, session);

                using (var transaction = session.BeginTransaction())
                {
                    var now = DateTime.Now;
                    foreach (var rid in recipeIds.Where(rid => !existing.Contains(rid)))
                    {
                        session.Save(
                            new QueuedRecipes
                                {
                                    Recipe = new Recipes { RecipeId = rid },
                                    UserId = identity.UserId,
                                    QueuedDate = now
                                });
                    }

                    transaction.Commit();
                }
            }
        }
        private static IList<Favorites> LoadRecipesInEachMenu(
            AuthorIdentity identity, 
            bool favouritesLoaded, 
            IList<Menus> databaseMenus, 
            ISession session)
        {
            ICriterion filter = favouritesLoaded
                                    ? Restrictions.Or(Restrictions.IsNull("Menu"), Restrictions.InG("Menu", databaseMenus))

                                    // Menu can be null, or in loaded menu list
                                    : Restrictions.InG("Menu", databaseMenus); // Menu must be in loaded menu list

            var favorites =
                session.QueryOver<Favorites>()
                    .Fetch(prop => prop.Recipe)
                    .Eager.Where(p => p.UserId == identity.UserId)
                    .Where(filter)
                    .List();
            return favorites;
        }
        public Menu[] GetMenus(AuthorIdentity identity, IList<Menu> menus, GetMenuOptions options)
        {
            using (var session = this.GetSession())
            {
                // menus will be null if all menus should be loaded, or a list of Menu objects to specify individual menus to load
                if (options == null)
                {
                    throw new ArgumentNullException("There are no menu options.");
                }

                if (identity == null)
                {
                    throw new ArgumentNullException("There are no identities.");
                }

                var favouritesLoaded = true;
                var query = session.QueryOver<Menus>().Where(p => p.UserId == identity.UserId);

                if (menus != null)
                {
                    favouritesLoaded = menus.Contains(Menu.Favorites);
                    query = LoadIndividualMenus(menus, query);
                }

                var databaseMenus = query.List();
                var favouriteMenus = new List<Menu>();

                if (favouritesLoaded)
                {
                    favouriteMenus.Add(Menu.Favorites);
                }

                favouriteMenus.AddRange(databaseMenus.Select(m => m.AsMenu()));

                if (!options.LoadRecipes)
                {
                    return favouriteMenus.ToArray();
                }

                var favorites = LoadRecipesInEachMenu(identity, favouritesLoaded, databaseMenus, session);

                return
                    favouriteMenus.Select(
                        m =>
                        new Menu(m)
                            {
                                Recipes =
                                    (m.Id.HasValue
                                         ? favorites.Where(f => f.Menu != null && f.Menu.MenuId == m.Id)
                                         : favorites.Where(f => f.Menu == null)).Select(
                                             r => r.Recipe.AsRecipeBrief()).ToArray()
                            }).ToArray();
            }
        }
        private static void MoveRecipesToAnotherMenu(
            AuthorIdentity identity, 
            MenuMove[] recipesMove, 
            ISession session, 
            IList<Favorites> databaseRecipes)
        {
            foreach (var moveAction in recipesMove)
            {
                Menus databaseTarget = null;
                if (moveAction.TargetMenu.HasValue)
                {
                    databaseTarget =
                        session.QueryOver<Menus>()
                            .Where(p => p.MenuId == moveAction.TargetMenu.Value)
                            .Where(p => p.UserId == identity.UserId)
                            .SingleOrDefault();

                    if (databaseTarget == null)
                    {
                        throw new MenuNotFoundException(moveAction.TargetMenu.Value);
                    }
                }

                var recipesToMove = moveAction.MoveAll
                                         ? databaseRecipes
                                         : databaseRecipes.Where(r => moveAction.RecipesToMove.Contains(r.Recipe.RecipeId));

                recipesToMove.ForEach(a => a.Menu = databaseTarget);
            }
        }
        public ShoppingList[] GetShoppingLists(
            AuthorIdentity identity, 
            IList<ShoppingList> lists, 
            GetShoppingListOptions options)
        {
            using (var session = this.GetSession())
            {
                var defaultsLoaded = true;
                var query = session.QueryOver<ShoppingLists>().Where(p => p.UserId == identity.UserId);

                defaultsLoaded = LoadIndividualLists(lists, defaultsLoaded, ref query);

                var databaseLists = query.List();
                var shopingList = new List<ShoppingList>();

                if (defaultsLoaded)
                {
                    shopingList.Add(ShoppingList.Default);
                }

                shopingList.AddRange(databaseLists.Select(l => l.AsShoppingList()));

                if (!options.LoadItems)
                {
                    return shopingList.ToArray();
                }

                var databaseItems = LoadItemsIntoLists(identity, defaultsLoaded, databaseLists, session);

                return
                    shopingList.Select(
                        m =>
                        new ShoppingList(
                            m.Id,
                            m.Title,
                            (m.Id.HasValue
                                 ? databaseItems.Where(f => f.ShoppingList != null && f.ShoppingList.ShoppingListId == m.Id)
                                 : databaseItems.Where(f => f.ShoppingList == null)).Select(r => r.AsShoppingListItem())))
                        .ToArray();
            }
        }
        public RecipeResult CreateRecipe(AuthorIdentity identity, Recipe recipe)
        {
            using (var session = this.GetSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    // Create Recipe
                    var databaseRecipe = new Recipes
                                       {
                                           Title = recipe.Title,
                                           Description = recipe.Description,
                                           CookTime = recipe.CookingTime,
                                           PrepTime = recipe.PreparationTime,
                                           Credit = recipe.Credit,
                                           CreditUrl = recipe.CreditUrl,
                                           DateEntered = recipe.DateEntered,
                                           ImageUrl = recipe.ImageUrl,
                                           Rating = recipe.AverageRating,
                                           ServingSize = recipe.ServingSize,
                                           Steps = recipe.Method
                                       };

                    session.Save(databaseRecipe);

                    CreateIngredients(recipe, databaseRecipe, session);

                    var databaseMetadata = CreateRecipeMetadata(recipe, databaseRecipe);

                    session.Save(databaseMetadata);
                    transaction.Commit();

                    return new RecipeResult { RecipeCreated = true, NewRecipeId = databaseRecipe.RecipeId };
                }
            }
        }
        public void RateRecipe(AuthorIdentity identity, Guid recipeId, Rating rating)
        {
            using (var currentSession = this.GetSession())
            {
                using (var transaction = currentSession.BeginTransaction())
                {
                    var existingRate =
                        currentSession.QueryOver<RecipeRatings>()
                            .Where(p => p.UserId == identity.UserId)
                            .Where(p => p.Recipe.RecipeId == recipeId)
                            .SingleOrDefault();

                    if (existingRate != null)
                    {
                        // Update existing
                        existingRate.Rating = (byte)rating;
                        currentSession.Update(existingRate);
                    }
                    else
                    {
                        // Create rating
                        currentSession.Save(
                            new RecipeRatings
                                {
                                    UserId = identity.UserId,
                                    Recipe = new Recipes { RecipeId = recipeId },
                                    Rating = (byte)rating
                                });
                    }

                    transaction.Commit();
                }
            }
        }
        public ShoppingListResult CreateShoppingList(AuthorIdentity identity, ShoppingList list)
        {
            using (var session = this.GetSession())
            {
                var shopingList = new ShoppingListResult();

                using (var transaction = session.BeginTransaction())
                {
                    var databaseList = new ShoppingLists();
                    databaseList.Title = list.Title.Trim();
                    databaseList.UserId = identity.UserId;
                    session.Save(databaseList);

                    CreateShopingList(list, databaseList, session);

                    transaction.Commit();

                    shopingList.NewShoppingListId = databaseList.ShoppingListId;
                }

                shopingList.List = list;
                return shopingList;
            }
        }
        public SearchResults RecipeSearch(AuthorIdentity identity, RecipeQuery query)
        {
            if (this.SearchProvider == null)
            {
                throw new NoConfiguredSearchProvidersException();
            }

            return this.SearchProvider.Search(identity, query);
        }
        public void DeleteMenus(AuthorIdentity identity, params Guid[] menuIds)
        {
            using (var session = this.GetSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    var databaseMenu =
                        session.QueryOver<Menus>()
                            .AndRestrictionOn(p => p.MenuId)
                            .IsInG(menuIds)
                            .Where(p => p.UserId == identity.UserId)
                            .Fetch(prop => prop.Recipes)
                            .Eager()
                            .List();

                    databaseMenu.ForEach(session.Delete);
                    transaction.Commit();
                }
            }
        }
        public ShoppingListResult UpdateShoppingList(
            AuthorIdentity identity, 
            Guid? listId, 
            Guid[] toRemove, 
            ShoppingListModification[] toModify, 
            IShoppingListSource[] toAdd, 
            string newName = null)
        {
            using (var session = this.GetSession())
            {
                using (var transaction = session.BeginTransaction())
                {
                    if (toRemove.Any())
                    {
                        DeleteItems(identity, listId, toRemove, session);
                    }

                    // Updates
                    ShoppingLists databaseList = null;
                    IList<ShoppingListItems> databaseItems = null;
                    if (listId.HasValue)
                    {
                        databaseList =
                            session.QueryOver<ShoppingLists>()
                                .Fetch(prop => prop.Items)
                                .Eager.Where(p => p.UserId == identity.UserId)
                                .Where(p => p.ShoppingListId == listId.Value)
                                .SingleOrDefault();

                        if (databaseList == null)
                        {
                            throw new ShoppingListNotFoundException();
                        }

                        if (!string.IsNullOrWhiteSpace(newName))
                        {
                            databaseList.Title = newName;
                        }

                        databaseItems = databaseList.Items;
                    }
                    else
                    {
                        databaseItems =
                            session.QueryOver<ShoppingListItems>()
                                .Where(p => p.UserId == identity.UserId)
                                .Where(p => p.ShoppingList == null)
                                .List();
                    }

                    ModifyShopingListItems(toModify, databaseItems);

                    return AddShopingListItems(identity, toAdd, databaseItems, databaseList, session, transaction);
                }
            }
        }
        public SearchResults Search(AuthorIdentity identity, RecipeQuery query)
        {
            using (var session = this.adapter.GetSession())
            {
                Recipes recipe = null;

                var recipesQuery = session.QueryOver(() => recipe).Where(p => !p.Hidden);

                if (!string.IsNullOrWhiteSpace(query.Keywords))
                {
                    // Add keyword search
                    recipesQuery =
                        recipesQuery.Where(
                            Restrictions.Or(
                                Restrictions.InsensitiveLike(
                                    "Title",
                                    string.Format("%{0}%", query.Keywords.Trim())),
                                Restrictions.InsensitiveLike("Description", string.Format("%{0}%", query.Keywords.Trim()))));
                }

                if (query.Time.MaxPrep.HasValue)
                {
                    recipesQuery = recipesQuery.Where(p => p.PrepTime <= query.Time.MaxPrep.Value);
                }

                if (query.Time.MaxCook.HasValue)
                {
                    recipesQuery = recipesQuery.Where(p => p.CookTime <= query.Time.MaxCook.Value);
                }

                if (query.Rating > 0)
                {
                    recipesQuery = recipesQuery.Where(p => p.Rating >= (int)query.Rating.Value);
                }

                recipesQuery = AddIngredientsToInclude(query, recipesQuery, recipe);

                recipesQuery = AddIngredientsToExclude(query, recipesQuery, recipe);

                if (query.Photos == PhotoFilter.Photo || query.Photos == PhotoFilter.HighRes)
                {
                    recipesQuery = recipesQuery.Where(Restrictions.IsNotNull("ImageUrl"));
                }

                if (query.Diet || query.Nutrition || query.Skill || query.Taste || (query.Meal != MealFilter.All)
                    || (query.Photos == PhotoFilter.HighRes))
                {
                    // Need to search in metadata
                    RecipeMetadata metadata = null;
                    recipesQuery = recipesQuery.JoinAlias(r => r.RecipeMetadata, () => metadata);

                    recipesQuery = SearchByMeal(query, recipesQuery, metadata);

                    recipesQuery = SearchByHighResolutionPhotos(query, recipesQuery, metadata);

                    recipesQuery = SearchByDiet(query, recipesQuery, metadata);

                    recipesQuery = SearchByNutrition(query, recipesQuery, metadata);

                    recipesQuery = SearchBySkill(query, recipesQuery, metadata);

                    recipesQuery = SearchByTaste(query, recipesQuery, metadata);
                }

                IQueryOverOrderBuilder<Recipes, Recipes> orderBy;
                switch (query.Sort)
                {
                    case SortOrder.Title:
                        orderBy = recipesQuery.OrderBy(p => p.Title);
                        break;
                    case SortOrder.PrepTime:
                        orderBy = recipesQuery.OrderBy(p => p.PrepTime);
                        break;
                    case SortOrder.CookTime:
                        orderBy = recipesQuery.OrderBy(p => p.CookTime);
                        break;
                    case SortOrder.Image:
                        orderBy = recipesQuery.OrderBy(p => p.ImageUrl);
                        break;
                    default:
                        orderBy = recipesQuery.OrderBy(p => p.Rating);
                        break;
                }

                var results =
                    (query.Direction == SortDirection.Descending ? orderBy.Desc() : orderBy.Asc()).Skip(query.Offset)
                        .Take(100)
                        .List();

                return new SearchResults
                           {
                               Briefs = results.Select(r => r.AsRecipeBrief()).ToArray(),
                               TotalCount = results.Count

                               // TODO: This needs to be the total matches, not the returned matches
                           };
            }
        }