// DELETE api/task/5
        public HttpResponseMessage Delete(int id)
        {
            if (id <= 0)
                return Request.CreateResponse(HttpStatusCode.NotFound, "id must be greater than zero");

            using (CrowdContext db = new CrowdContext())
            {
                var task = db.ParticipantTasks.Single(c => c.Id.Equals(id));
                if (task == null)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }
                db.ParticipantTasks.Remove(task);
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK, task);
            }
        }
        // DELETE api/Activity/5
        public HttpResponseMessage Delete(int id)
        {
            if (id <= 0)
                return Request.CreateResponse(HttpStatusCode.NotFound, "id must be greater than zero");

            using (CrowdContext db = new CrowdContext())
            {
                var activity = db.ParticipantActivities.Find(id);
                if (activity == null)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }
                db.ParticipantActivities.Remove(activity);
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK, activity);
            }
        }
        // DELETE api/ActivityResult/5
        public async Task<HttpResponseMessage> Delete(int id)
        {
            if (id <= 0)
                return Request.CreateResponse(HttpStatusCode.BadRequest, "id must be greater than zero");

            using (CrowdContext db = new CrowdContext())
            {
                User user = await AuthenticateUser(GetAuthentication(), db);
                if (user == null)
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }

                var result = db.ParticipantResults.Find(id);
                if (result == null)
                {
                    return Request.CreateResponse(HttpStatusCode.NotFound);
                }

                if (result.User != user && !user.IsAdmin)
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }

                db.ParticipantResults.Remove(result);
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK, result);
            }
        }
        public async Task<HttpResponseMessage> Post(ParticipantResult result)
        {
            using (CrowdContext db = new CrowdContext())
            {
                User user = await AuthenticateUser(GetAuthentication(), db);
                if (user == null)
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }

                if (!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                if (result == null)
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Activity result cannot be null");

                result.User = user;
                result.UploadedAt = DateTime.Now;
                result = db.ParticipantResults.Add(result);
                user.Submissions.Add(result);
                if (result.IsAssessment)
                {
                    user.LastAssessment = result;
                }

                try
                {
                    db.SaveChanges();
                }
                catch (Exception ex)
                {
                    return Request.CreateResponse(HttpStatusCode.ExpectationFailed, ex.Message);
                }
                SvcStatus status = await CrowdFlowerApi.CreateJob(result,
                    await db.ParticipantActivities.FindAsync(result.ParticipantActivityId));

                if (status.Level == 0)
                {
                    string json = await status.Response.Content.ReadAsStringAsync();
                    CFJobResponse jobRes = JsonConvert.DeserializeObject<CFJobResponse>(json);

                    result.CrowdJobId = jobRes.id;

                    if (status.CreatedRows != null)
                    {
                        foreach (CrowdRowResponse row in status.CreatedRows)
                        {
                            db.CrowdRowResponses.Add(row);
                        }
                    }

                    try
                    {
                        db.SaveChanges();
                    }
                    catch (Exception e)
                    {
                        throw new HttpResponseException(Request.CreateResponse(
                            HttpStatusCode.ExpectationFailed, e.Message));
                    }

                    status = CrowdFlowerApi.LaunchJob(jobRes.id, status.Count);
                    return status.Response;
                }
                db.DebugMessages.Add(new DebugMessage
                {
                    Message = status.Description,
                    Filename = "ActivityResultController",
                    FunctionName = "Post"
                });
                await db.SaveChangesAsync();
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, status.Description + " \n\n " + status.Response.ToString());
            }
        }
        // PUT api/ActivityResult/5
        public async Task<HttpResponseMessage> Put(int id, ParticipantResult result)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
            if (id != result.Id)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            using (CrowdContext db = new CrowdContext())
            {
                User user = await AuthenticateUser(GetAuthentication(), db);
                if (user == null || !user.IsAdmin)
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }

                db.ParticipantResults.Attach(result);
                db.Entry(result).State = EntityState.Modified;
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK);
            }
        }
        // PUT api/Category/5
        public async Task<HttpResponseMessage> Put(ParticipantActivityCategory category)
        {
            using (CrowdContext db = new CrowdContext())
            {
                User user = await AuthenticateUser(GetAuthentication(), db);
                if (user == null)
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }

                if (!ModelState.IsValid)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                }
                if (category.Id <= 0)
                {
                    return Request.CreateResponse(HttpStatusCode.BadRequest);
                }
                db.ParticipantActivityCategories.Attach(category);
                db.Entry(category).State = EntityState.Modified;
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK);
            }
        }
        // DELETE api/Category/5
        public async Task<HttpResponseMessage> Delete(int id)
        {
            using (CrowdContext db = new CrowdContext())
            {
                User user = await AuthenticateUser(GetAuthentication(), db);
                if (user == null)
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }

                if (id <= 0)
                    return Request.CreateResponse(HttpStatusCode.BadRequest, "id must be greater than zero");
                var category = db.ParticipantActivityCategories.Find(id);
                if (category == null)
                {
                    throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest));
                }
                db.ParticipantActivityCategories.Remove(category);
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK, category);
            }
            
        }
        // POST api/Category
        public async Task<HttpResponseMessage> Post(ParticipantActivityCategory category)
        {
            using (CrowdContext db = new CrowdContext())
            {
                User user = await AuthenticateUser(GetAuthentication(), db);
                if (user == null)
                {
                    return new HttpResponseMessage(HttpStatusCode.Unauthorized);
                }

                if (!ModelState.IsValid) return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);

                db.ParticipantActivityCategories.Add(category);
                db.SaveChanges();
                var response = Request.CreateResponse(HttpStatusCode.Created, category);
                response.Headers.Location = new Uri(Request.RequestUri.AbsoluteUri + category.Id);//new Uri(Url.Link("DefaultApi", new { id = category.Key }));
                return response;
            }
        }
        // POST api/task
        public HttpResponseMessage Post(ParticipantTask task)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }

            using (CrowdContext db = new CrowdContext())
            {
                db.ParticipantTasks.Add(task);
                db.SaveChanges();
                var response = Request.CreateResponse(HttpStatusCode.Created, task);
                //response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = task.Key }));
                return response;
            }
        }
        // PUT api/task/5
        public HttpResponseMessage Put(int id, ParticipantTask task)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }
            if (id != task.Id)
            {
                return Request.CreateResponse(HttpStatusCode.BadRequest);
            }

            using (CrowdContext db = new CrowdContext())
            {
                db.ParticipantTasks.Attach(task);
                db.Entry(task).State = EntityState.Modified;
                try
                {
                    db.SaveChanges();
                }
                catch (DbUpdateConcurrencyException ex)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                }
                return Request.CreateResponse(HttpStatusCode.OK);
            }
        }
        // Should always return OK - crowdflower can't really do anything with errors. Log any errors in the database.
        public async Task<HttpResponseMessage> Post()
        {
            var req = this.Request;
            string content = "Not done yet";
            IEnumerable<string> contentTypes = new[]{""};

            try
            {
                Request.Headers.TryGetValues("Content-Type", out contentTypes);

                content = (await req.Content.ReadAsFormDataAsync())["payload"];

                CFResponseData cfData = JsonConvert.DeserializeObject<CFResponseData>(content);

                if (cfData == null || cfData.results == null || cfData.results.judgments.Count <= 0)
                    return Request.CreateResponse(HttpStatusCode.OK);

                using (CrowdContext db = new CrowdContext())
                {
                    int taskId = cfData.results.judgments[0].unit_id;
                    CrowdRowResponse resp = await db.CrowdRowResponses.FindAsync(taskId.ToString());

                    resp.TaskType = cfData.data.TaskType;
                    resp.Choices = cfData.data.Choices;
                    resp.PrevLoud = cfData.data.PrevLoud;
                    resp.PrevPace = cfData.data.PrevPace;
                    resp.PrevPitch = cfData.data.PrevPitch;
                    resp.Comparison = cfData.data.Comparison;
                    resp.ExtraData = cfData.data.ExtraData;

                    if (resp.TaskJudgements == null) resp.TaskJudgements = new List<CrowdJudgement>();

                    foreach (Judgement judgement in cfData.results.judgments)
                    {
                        if (resp.TaskJudgements.Any(judge =>
                            judge.WorkerId == judgement.worker_id &&
                            judge.CrowdRowResponseId == resp.Id
                            )) continue;

                        CrowdJudgement cJudgement = new CrowdJudgement
                        {
                            Id = judgement.id,
                            City = judgement.city,
                            Country = judgement.country,
                            JobId = judgement.job_id,
                            CrowdRowResponseId = resp.Id,
                            Tainted = judgement.tainted,
                            Trust = judgement.trust,
                            WorkerId = judgement.worker_id,
                            CreatedAt = DateTime.Now
                        };
                        resp.TaskJudgements.Add(cJudgement);
                        db.CrowdJudgements.Add(cJudgement);

                        await cJudgement.AddData(judgement.data, db);
                    }

                    db.SaveChanges();

                    return Request.CreateResponse(HttpStatusCode.OK);
                }
            }
            catch (Exception ex)
            {
                using (CrowdContext db = new CrowdContext())
                {
                    db.DebugMessages.Add(new DebugMessage
                    {
                        Message = ex + "\nSENT CONTENT: " + content +", content-type: " + contentTypes,
                        Filename = "CFWebhookController",
                        FunctionName = "Post"
                    });
                    db.SaveChanges();
                }
                return Request.CreateResponse(HttpStatusCode.OK); 
            }
        }
        // POST api/Activity
        public HttpResponseMessage Post(ParticipantActivity activity)
        {
            if (!ModelState.IsValid)
            {
                return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
            }

            using (CrowdContext db = new CrowdContext())
            {
                db.ParticipantActivities.Add(activity);
                db.SaveChanges();
                var response = Request.CreateResponse(HttpStatusCode.Created, activity);
                return response;
            }
        }