/// <summary>
        /// This method adds a new question to the database and saves this in a variable
        /// </summary>
        private void initializeTestData()
        {
            using (IntelliCloudContext ctx = new IntelliCloudContext())
            {
                UserEntity newUser = new UserEntity();
                newUser.CreationTime = DateTime.UtcNow;
                newUser.FirstName = "integration";
                newUser.LastName = "test";
                newUser.Type = Common.DataTransfer.UserType.Customer;

                ctx.Users.Add(newUser);
                ctx.SaveChanges();

                UserEntity newEmployee = new UserEntity();
                newEmployee.CreationTime = DateTime.UtcNow;
                newEmployee.FirstName = "employee";
                newEmployee.Type = Common.DataTransfer.UserType.Employee;

                ctx.Users.Add(newEmployee);
                ctx.SaveChanges();

                this.employee = newEmployee;

                SourceEntity newSource = new SourceEntity();
                newSource.User = newUser;
                newSource.Value = "*****@*****.**";
                newSource.CreationTime = DateTime.UtcNow;
                newSource.SourceDefinition = new SourceDefinitionEntity { CreationTime = DateTime.UtcNow, Description = "integration test def", Name = "test def", Url = "" };

                ctx.Sources.Add(newSource);
                ctx.SaveChanges();

                QuestionEntity newEntity = new QuestionEntity();
                newEntity.IsPrivate = false;
                newEntity.LanguageDefinition = new LanguageDefinitionEntity { Name = "English", ResourceName = "English" };
                newEntity.QuestionState = Common.DataTransfer.QuestionState.Open;
                newEntity.Source = new QuestionSourceEntity { Source = newSource, PostId = "" };
                newEntity.Title = "this is a test question";
                newEntity.User = newUser;
                newEntity.Content = "this is the question i want to ask, please help me?";
                newEntity.CreationTime = DateTime.UtcNow;
                newEntity.FeedbackToken = "feedbackyeah!!@#$%^&*()";

                ctx.Questions.Add(newEntity);
                ctx.SaveChanges();

                this.entity = newEntity;
            }
        }
        /// <summary>
        /// This method adds a new question to the database and saves this in a variable
        /// </summary>
        private void initializeTestData()
        {
            using (IntelliCloudContext ctx = new IntelliCloudContext())
            {
                UserEntity newEmployee = new UserEntity();
                newEmployee.CreationTime = DateTime.UtcNow;
                newEmployee.FirstName = "employee";
                newEmployee.Type = Common.DataTransfer.UserType.Employee;

                ctx.Users.Add(newEmployee);
                ctx.SaveChanges();

                this.employee = newEmployee;

                AnswerEntity newAnswer = new AnswerEntity();
                newAnswer.CreationTime = DateTime.UtcNow;
                newAnswer.Content = "Integration test for answer";
                newAnswer.AnswerState = AnswerState.UnderReview;
                newAnswer.IsPrivate = false;
                newAnswer.LanguageDefinition = new LanguageDefinitionEntity() {Name = "Dutch", ResourceName = "NL"};
                newAnswer.User = newEmployee;

                ctx.Answers.Add(newAnswer);
                ctx.SaveChanges();

                this.answer = newAnswer;

                ReviewEntity newReview = new ReviewEntity();
                newReview.CreationTime = DateTime.UtcNow;
                newReview.Content = "Integration test for review";
                newReview.ReviewState = ReviewState.Open;
                newReview.User = newEmployee;
                newReview.Answer = newAnswer;

                ctx.Reviews.Add(newReview);
                ctx.SaveChanges();

                this.review = newReview;

            }
        }
        public void UpdateReview(string reviewId, ReviewState reviewState)
        {
            Validation.IdCheck(reviewId);

            using (var context = new IntelliCloudContext())
            {
                var id = Convert.ToInt32(reviewId);
                ReviewEntity review = context.Reviews.SingleOrDefault(r => r.Id.Equals(id));
                if (review != null)
                {
                    review.ReviewState = reviewState;

                    context.SaveChanges();
                }
                else
                {
                    throw new NotFoundException("Sequence contains no elements");
                }
            }
        }
        public void CreateReview(int employeeId, int answerId, string review)
        {
            Validation.IdCheck(answerId);
            Validation.IdCheck(employeeId);
            Validation.StringCheck(review);

            using (var context = new IntelliCloudContext())
            {
                ReviewEntity reviewEntity = new ReviewEntity();
                var answer = context.Answers.SingleOrDefault(q => q.Id.Equals(answerId));
                if (review != null)
                {
                    reviewEntity.Answer = answer;
                }
                else
                {
                    throw new NotFoundException("Sequence contains no elements");
                }

                var user = context.Users.SingleOrDefault(u => u.Id.Equals(employeeId));
                if (user != null)
                {
                    reviewEntity.User = user;
                }
                else
                {
                    throw new NotFoundException("Sequence contains no elements");
                }

                reviewEntity.Content = review;
                reviewEntity.ReviewState = ReviewState.Open;

                context.Reviews.Add(reviewEntity);

                context.SaveChanges();
            }
        }
        public void CreateQuestion(
            string source, string reference, string question, string title, string postId = null, bool isPrivate = false)
        {
            Validation.StringCheck(source);
            Validation.StringCheck(reference);
            Validation.StringCheck(question);
            Validation.StringCheck(title);

            using (IntelliCloudContext ctx = new IntelliCloudContext())
            {
                // TODO determine real language 
                LanguageDefinitionEntity languageDefinition = ctx.LanguageDefinitions.SingleOrDefault(ld => ld.Name.Equals("English"));

                // TODO remove exception as you probably want to create the language if it doesn't exist.
                if (languageDefinition == null)
                    throw new NotFoundException("No languageDefinition entity exists with the specified ID.");

                SourceDefinitionEntity sourceDefinition = ctx.SourceDefinitions.SingleOrDefault(sd => sd.Name.Equals(source));

                if (sourceDefinition == null)
                    throw new NotFoundException("The provided source doesn't exists.");

                // Check if the user already exists
                SourceEntity sourceEntity = ctx.Sources.SingleOrDefault(s => s.SourceDefinition.Id == sourceDefinition.Id && s.Value == reference);

                UserEntity userEntity;

                if (sourceEntity != null)
                {
                    // user already has an account, use this
                    userEntity = ctx.Users.Single(u => u.Id == sourceEntity.UserId);
                }
                else
                {
                    // user has no account, create one
                    userEntity = new UserEntity()
                    {
                        CreationTime = DateTime.UtcNow,
                        Type = UserType.Customer
                    };

                    ctx.Users.Add(userEntity);

                    // Mount the source to the new user
                    sourceEntity = new SourceEntity()
                    {
                        Value = reference,
                        CreationTime = DateTime.UtcNow,
                        SourceDefinition = sourceDefinition,
                        User = userEntity,
                    };

                    ctx.Sources.Add(sourceEntity);
                }

                QuestionEntity questionEntity = new QuestionEntity()
                {
                    Content = question,
                    CreationTime = DateTime.UtcNow,
                    IsPrivate = isPrivate,
                    QuestionState = QuestionState.Open,
                    Title = title,
                    Source = new QuestionSourceEntity()
                    {
                        Source = sourceEntity,
                        PostId = postId
                    },
                    LanguageDefinition = languageDefinition,
                    User = userEntity
                };

                ctx.Questions.Add(questionEntity);

                ctx.SaveChanges();
            }
        }
        public void UpdateQuestion(int id, int employeeId)
        {
            Validation.IdCheck(id);
            Validation.IdCheck(employeeId);

            using (IntelliCloudContext ctx = new IntelliCloudContext())
            {
                QuestionEntity questionEntity = (from q in ctx.Questions
                                                 where q.Id == id
                                                 select q).Single();

                questionEntity.Answerer = (from u in ctx.Users
                                           where u.Id == employeeId
                                           select u).Single();
                ctx.SaveChanges();
            }

        }
        /// <summary>
        /// Updates the answer with the given identifier.
        /// </summary>
        /// <param name="id">The identifier of the answer that is updated.</param>
        /// <param name="answerState">The new state of the answer.</param>
        /// <param name="answer">The new content of the given answer.</param>
        public void UpdateAnswer(string id, AnswerState answerState, string answer)
        {
            Validation.IdCheck(id);
            Validation.StringCheck(answer);

            using (var ctx = new IntelliCloudContext())
            {
                int iId = Convert.ToInt32(id);

                AnswerEntity answerEntity = (from a in ctx.Answers
                                                 .Include(a => a.User)
                                                 .Include(a => a.LanguageDefinition)
                                             where a.Id == iId
                                             select a).SingleOrDefault();

                if (answerEntity == null)
                    throw new NotFoundException("No answer entity exists with the specified ID.");

                answerEntity.AnswerState = answerState;
                answerEntity.Content = answer;

                ctx.SaveChanges();

            }
        }
        /// <summary>
        /// Creates a new answer.
        /// </summary>
        /// <param name="questionId">The identifier of the question which is answered.</param>
        /// <param name="answer">The content of the given answer.</param>
        /// <param name="answererId">The employee who answered the question.</param>
        /// <param name="answerState">The state of the answer.</param>
        public void CreateAnswer(int questionId, string answer, int answererId, AnswerState answerState)
        {
            Validation.IdCheck(answererId);
            Validation.IdCheck(questionId);
            Validation.StringCheck(answer);

            using (var ctx = new IntelliCloudContext())
            {

                AnswerEntity answerEntity = new AnswerEntity();

                answerEntity.AnswerState = answerState;
                answerEntity.Content = answer;
                answerEntity.CreationTime = DateTime.UtcNow;

                UserEntity user = ctx.Users.SingleOrDefault(ld => ld.Id == answererId);

                if (user == null)
                    throw new NotFoundException("No user entity exists with the specified ID.");

                answerEntity.User = user;
                // TODO link answer to question and generate a feedbackToken using GUID (can both be set in the question).
                // TODO set IsPrivate based on private settings in question.
                answerEntity.IsPrivate = false;

                // TODO determine real language 
                LanguageDefinitionEntity languageDefinition = ctx.LanguageDefinitions.SingleOrDefault(ld => ld.Name.Equals("English"));

                if (languageDefinition == null)
                    throw new NotFoundException("No languageDefinition entity exists with the specified ID.");

                answerEntity.LanguageDefinition = languageDefinition;

                ctx.Answers.Add(answerEntity);

                ctx.SaveChanges();

            }

            // TODO put the SendAnswerFactory in the BaseManager.
            // TODO send the answer using the this.SendAnswerFactory.LoadPlugin(question.Source.Source.SourDefinition).SendAnswer(question, answer) method.
        }
        /// <summary>
        /// Method used for creating a new user.
        /// </summary>
        /// <param name="type">The type of user. Required.</param>
        /// <param name="sources">A list of UserSource instances. Required (must contain at least one item).</param>
        /// <param name="firstName">The user's first name. Optional.</param>
        /// <param name="infix">The user's infix. Optional.</param>
        /// <param name="lastName">The user's last name. Optional.</param>
        public void CreateUser(UserType type, IList<UserSource> sources, string firstName = null, string infix = null, string lastName = null)
        {
            // Validate supplied input data
            if (firstName != null) Validation.StringCheck(firstName);
            if (infix != null) Validation.StringCheck(infix);
            if (lastName != null) Validation.StringCheck(lastName);

            using (IntelliCloudContext context = new IntelliCloudContext())
            {
                // Create a new user based on the retrieved user info
                UserEntity userEntity = new UserEntity()
                {
                    FirstName = firstName,
                    Infix = infix,
                    LastName = lastName,
                    Type = type,
                    CreationTime = DateTime.UtcNow
                };
                context.Users.Add(userEntity);

                // Add all supplied sources to the user
                foreach (UserSource source in sources)
                {
                    // Check if the source is defined
                    Validation.SourceDefinitionExistsCheck(source.Name);

                    // Create a new source for the source definition
                    SourceDefinitionEntity sourceDefinition = context.SourceDefinitions.SingleOrDefault(sd => sd.Name.Equals(source.Name));
                    SourceEntity sourceEntity = new SourceEntity()
                    {
                        Value = source.Value,
                        CreationTime = DateTime.UtcNow,
                        SourceDefinition = sourceDefinition,
                        User = userEntity,
                    };
                    context.Sources.Add(sourceEntity);
                }

                // Save the changes to the context
                context.SaveChanges();
            }
        }
        /// <summary>
        /// Method for creating a new user based on an instance of class OpenIDUserInfo.
        /// </summary>
        /// <param name="userInfo">The instance of class OpenIDUserInfo that will be used to create the new user.</param>
        /// <param name="createdUser">Reference to an object of class User - will be set to an instance of class User on success or null if the user could not be created.</param>
        /// <returns>Boolean value indicating if the user could be created.</returns>
        public bool TryCreateNewUser(OpenIDUserInfo userInfo, out User createdUser)
        {
            // User object that will contain the newly created User object on success
            createdUser = null;

            // Only attempt to create a new user when an instance of class OpenIDUserInfo has been supplied
            if (userInfo != null)
            {
                // No user could be matched; create a new user based on the retrieved user info
                UserEntity userEntity = null;
                using (IntelliCloudContext context = new IntelliCloudContext())
                {
                    // Create a new user based on the retrieved user info
                    userEntity = new UserEntity()
                    {
                        FirstName = userInfo.GivenName,
                        LastName = userInfo.FamilyName,
                        Type = UserType.Customer,
                        CreationTime = DateTime.UtcNow
                    };
                    context.Users.Add(userEntity);

                    // Create a new source for the user's email address
                    SourceDefinitionEntity mailSourceDefinition = context.SourceDefinitions.SingleOrDefault(sd => sd.Name.Equals("Mail"));
                    SourceEntity mailSourceEntity = new SourceEntity()
                    {
                        Value = userInfo.Email,
                        CreationTime = DateTime.UtcNow,
                        SourceDefinition = mailSourceDefinition,
                        User = userEntity,
                    };
                    context.Sources.Add(mailSourceEntity);

                    // Create a new source for the user's id from the issuer
                    SourceDefinitionEntity issuerSourceDefinition = context.SourceDefinitions.SingleOrDefault(sd => sd.Name.Equals(userInfo.Issuer));
                    SourceEntity issuerSourceEntity = new SourceEntity()
                    {
                        Value = userInfo.Sub,
                        CreationTime = DateTime.UtcNow,
                        SourceDefinition = issuerSourceDefinition,
                        User = userEntity,
                    };
                    context.Sources.Add(issuerSourceEntity);

                    // Save the changes to the context
                    context.SaveChanges();
                }

                // Convert the UserEntity instance to an instance of class User and set it in the matchedUser variable
                createdUser = this.convertEntities.UserEntityToUser(userEntity);
            }

            // Return true or false indicating if the user has been created
            return (createdUser != null) ? true : false;
        }
        /// <summary>
        /// Method for matching a user based on an instance of class OpenIDUserInfo.
        /// </summary>
        /// <param name="userInfo">The instance of class OpenIDUserInfo that will be used to match a user.</param>
        /// <param name="matchedUser">Reference to an object of class User - will be set to an instance of class User on success or null if no user could be matched.</param>
        /// <returns>Boolean value indicating if a user could be matched.</returns>
        public bool TryMatchUser(OpenIDUserInfo userInfo, out User matchedUser)
        {
            // User object that will contain the matched User object on success
            matchedUser = null;

            // Only attempt to match a user when an instance of class OpenIDUserInfo has been supplied
            if (userInfo != null)
            {
                using (IntelliCloudContext context = new IntelliCloudContext())
                {
                    // Get the user entity from the context
                    UserEntity userEntity = context.Users
                                            .Include(u => u.Sources.Select(s => s.SourceDefinition))
                                            .SingleOrDefault(s => s.Sources.Any(a => (a.SourceDefinition.Name == "Mail" && a.Value == userInfo.Email) || (a.SourceDefinition.Name == userInfo.Issuer && a.Value == userInfo.Sub)));

                    // Only continue if the user entity was found
                    if (userEntity != null)
                    {
                        // Update the user's first name and last name
                        userEntity.FirstName = userInfo.GivenName;
                        userEntity.LastName = userInfo.FamilyName;

                        // Update the user's id from the issuer
                        userEntity.Sources.Where(s => s.SourceDefinition.Name == userInfo.Issuer)
                                          .Select(s => { s.Value = userInfo.Sub; return s; });

                        // Save the changes to the context
                        context.SaveChanges();

                        // Convert the UserEntity to an instance of class User and set in the reference
                        matchedUser = this.convertEntities.UserEntityToUser(userEntity);
                    }
                }
            }

            // Return true or false indicating if a user could be matched
            return (matchedUser != null) ? true : false;
        }
        public void Cleanup()
        {
            using (IntelliCloudContext ctx = new IntelliCloudContext())
            {
                ctx.Reviews.RemoveRange(ctx.Reviews.ToList());
                ctx.Answers.RemoveRange(ctx.Answers.ToList());
                ctx.Users.RemoveRange(ctx.Users.ToList());

                ctx.SaveChanges();
            }
        }
        public void Cleanup()
        {
            using (IntelliCloudContext ctx = new IntelliCloudContext())
            {
                ctx.Questions.RemoveRange(ctx.Questions.ToList());
                ctx.QuestionSources.RemoveRange(ctx.QuestionSources.ToList());
                ctx.Sources.RemoveRange(ctx.Sources.ToList());
                ctx.SourceDefinitions.RemoveRange(ctx.SourceDefinitions.ToList());
                ctx.LanguageDefinitions.RemoveRange(ctx.LanguageDefinitions.ToList());
                ctx.Users.RemoveRange(ctx.Users.ToList());

                ctx.SaveChanges();
            }
        }
        /// <summary>
        /// Method used for saving user feedback for an answer.
        /// </summary>
        /// <param name="feedback">The textual feedback given by the user.</param>
        /// <param name="answerId">The id of the answer for which the feedback has been given.</param>
        /// <param name="questionId">The id of the question to which the answer is assigned.</param>
        /// <param name="feedbackType">The type of feedback which indicates if the user accepted or declined the answer.</param>
        /// <param name="feedbackToken">The feedback token is required to provide feedback to answers on a question. It
        /// is used to make sure the user that asked the question is also the user giving the feedback and that feedback
        /// can only be given once.</param>
        public void CreateFeedback(string feedback, int answerId, int questionId, FeedbackType feedbackType, string feedbackToken)
        {
            // Validate input data
            Validation.StringCheck(feedback);
            Validation.IdCheck(answerId);
            Validation.IdCheck(questionId);
            Validation.StringCheck(feedbackToken);

            using (IntelliCloudContext context = new IntelliCloudContext())
            {
                // Get the answer entity from the context
                AnswerEntity answer = context.Answers
                    .Include(a => a.User)
                    .Include(a => a.User.Sources)
                    .Include(a => a.LanguageDefinition)
                    .SingleOrDefault(a => a.Id == answerId);

                if (answer == null)
                    throw new NotFoundException("No answer entity exists with the specified ID.");

                // Set the state of the answer to UnderReview - employee needs to process the feedback given by the user
                answer.AnswerState = AnswerState.UnderReview;

                // Get the question entity from the context
                QuestionEntity question = context.Questions
                                          .Include(q => q.User)
                                          .Include(q => q.User.Sources)
                                          .Include(q => q.Source)
                                          .Include(q => q.LanguageDefinition)
                                          .Include(q => q.Answer)
                                          .Include(q => q.Answer.LanguageDefinition)
                                          .Include(q => q.Answer.User)
                                          .Include(q => q.Answer.User.Sources)
                                          .Include(q => q.Answerer)
                                          .Include(q => q.Answerer.Sources)
                                          .SingleOrDefault(q => q.Id == questionId);

                if (question == null)
                    throw new NotFoundException("No question entity exists with the specified ID.");

                // Check if the user who asked the question is the one to posted the feedback and make sure feedback is
                // only given once.
                if (question.FeedbackToken != feedbackToken)
                    throw new InvalidOperationException(
                        "Feedback can only be given once by the user who asked the question.");
                
                // Set the state of the question to Open - employee needs to process the feedback given by the user
                question.QuestionState = QuestionState.Open;
                // Reset token so feedback can only be given once.
                question.FeedbackToken = null;

                // Store the user's feedback for the given answer
                FeedbackEntity feedbackEntity = new FeedbackEntity();
                feedbackEntity.Question = question;
                feedbackEntity.Answer = answer;
                feedbackEntity.Content = feedback;
                feedbackEntity.CreationTime = DateTime.UtcNow;
                feedbackEntity.FeedbackState = FeedbackState.Open;
                feedbackEntity.FeedbackType = feedbackType;
                feedbackEntity.User = question.User;
                context.Feedbacks.Add(feedbackEntity);

                // Save the changes to the context
                context.SaveChanges();
            }
        }
        /// <summary>
        /// Method used for updating the state of an existing feedback entry.
        /// </summary>
        /// <param name="id">The id of the feedback entry to update.</param>
        /// <param name="feedbackState">The new state of the feedback entry.</param>
        public void UpdateFeedback(string id, FeedbackState feedbackState)
        {
            // Validate input data
            Validation.IdCheck(id);

            // Convert the textual representation of the id to an integer
            int iFeedbackId = Convert.ToInt32(id);

            using (IntelliCloudContext context = new IntelliCloudContext())
            {
                // Get the feedback entity from the context
                FeedbackEntity feedback = context.Feedbacks
                    .Include(f => f.Question)
                    .Include(f => f.User)
                    .Include(f => f.Answer)
                    .SingleOrDefault(f => f.Id == iFeedbackId);

                if (feedback == null)
                    throw new NotFoundException("No feedback entity exists with the specified ID.");

                // Update the state of the feedback entry
                feedback.FeedbackState = feedbackState;

                // Save the changes to the context
                context.SaveChanges();
            }
        }