public HttpResponseMessage CloseVersion([FromUri] string versionNumber)
        {
            long version;
            if (!long.TryParse(versionNumber, out version))
            {
                return Request.CreateBadRequestResponse();
            }

            User user = RequestContext.GetAuthenticatedUser();
            Device device = RequestContext.GetDevice();

            using (IDatabaseService database = new DatabaseService())
            {
                if (!database.HasIndiagramVersion(user.Id, version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Version not found");
                }

                Version v = database.CloseVersion(user.Id, device.Id, version);
                if (v == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Version not found");
                }

                return Request.CreateGoodReponse(ToResponse(v));
            }
        }
 public HttpResponseMessage All()
 {
     using (IDatabaseService database = new DatabaseService())
     {
         Device device = RequestContext.GetDevice();
         return Request.CreateGoodReponse(database.GetSettings(device).Select(x => new SettingsResponse(x.SerializedSettings, x.VersionNumber, x.Date)).ToList());
     }
 }
        public HttpResponseMessage Versions()
        {
            User user = RequestContext.GetAuthenticatedUser();

            using (IDatabaseService database = new DatabaseService())
            {
                return Request.CreateGoodReponse(database.GetVersions(user.Id).Select(ToResponse));
            }
        }
        public HttpResponseMessage ListDevices()
        {
            User user = RequestContext.GetAuthenticatedUser();

            using(IDatabaseService database = new DatabaseService())
            {
                List<Device> devices = database.GetDevices(user).ToList();

                return Request.CreateGoodReponse(devices.Select(x => new DeviceResponse(x.DeviceName)).ToList());
            }
        }
        public HttpResponseMessage CreateVersion()
        {
            User user = RequestContext.GetAuthenticatedUser();
            Device device = RequestContext.GetDevice();

            using (IDatabaseService database = new DatabaseService())
            {
                Version version = database.CreateVersion(user.Id, device.Id);

                return Request.CreateGoodReponse(ToResponse(version));
            }
        }
        public HttpResponseMessage All()
        {
            using (IDatabaseService database = new DatabaseService())
            {
                Device device = RequestContext.GetDevice();

                List<IndiagramForDevice> collection = database.GetIndiagrams(device);
                List<IndiagramResponse> indiagrams = GetCollectionTree(collection);

                return Request.CreateGoodReponse(indiagrams);
            }
        }
        public HttpResponseMessage Last()
        {
            using (IDatabaseService database = new DatabaseService())
            {
                Device device = RequestContext.GetDevice();
                Settings settings = database.GetLastSettings(device);

                if (settings == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No settings synced");
                }
                return Request.CreateGoodReponse(new SettingsResponse(settings.SerializedSettings, settings.VersionNumber, settings.Date));
            }
        }
        public HttpResponseMessage PostSound([FromUri] string id, [FromUri] string versionNumber, [FromBody] FileUploadRequest fileRequest)
        {
            using (IDatabaseService database = new DatabaseService())
            {
                User user = RequestContext.GetAuthenticatedUser();
                Device device = RequestContext.GetDevice();
                long indiagramId;
                long version;

                if (!long.TryParse(id, out indiagramId) || !long.TryParse(versionNumber, out version))
                {
                    return Request.CreateBadRequestResponse();
                }

                if (!database.HasIndiagramVersion(user.Id, version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Version not found");
                }

                if (!database.CanPushInVersion(device.UserId, device.Id, version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Can not update in this version, version is closed or didn't created by this device");
                }

                IndiagramInfo indiagramInfo = database.GetLastIndiagramInfo(user.Id, indiagramId);

                if (indiagramInfo == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Indiagram not found");
                }

                if (indiagramInfo.Version != version)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Can not modify old indiagram version");
                }

                string filename = fileRequest.Filename;
                byte[] buffer = fileRequest.Content;

                IStorageService storageService = new StorageService();
                if (!storageService.UploadSound(indiagramInfo, buffer))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Conflict, "Indiagram sound already exists and can't be replaced");
                }

                database.SetIndiagramSound(indiagramInfo, filename, buffer);
                return Request.CreateEmptyGoodReponse();
            }
        }
        public HttpResponseMessage Login([FromBody] UserLoginRequest userInfo)
        {
            if (string.IsNullOrWhiteSpace(userInfo.Login) || string.IsNullOrWhiteSpace(userInfo.Password))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                if (!database.CheckAuthentification(userInfo.Login, userInfo.Password))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "Invalid credentials");
                }

                return Request.CreateEmptyGoodReponse();
            }
        }
		public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
		{
			HttpRequestMessage request = context.Request;

			string login = request.GetHeaderValue("x-indiarose-login");
			string password = request.GetHeaderValue("x-indiarose-password");

			if (string.IsNullOrWhiteSpace(login) || string.IsNullOrWhiteSpace(password))
			{
				context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
				return;
			}

			using (IDatabaseService database = new DatabaseService())
			{
				if (database.CheckAuthentification(login, password))
				{
					AuthentificationPrincipal identity = new AuthentificationPrincipal(database.GetUserByLogin(login), password);

					string deviceName = request.GetHeaderValue("x-indiarose-device");
					if (!string.IsNullOrWhiteSpace(deviceName))
					{
						identity.Device = database.GetDevice(identity.User, deviceName);

						if (identity.Device == null && _deviceRequired)
						{
							context.ErrorResult = new AuthenticationFailureResult("Invalid device name", request);
							return;
						}
					}
					else if (_deviceRequired)
					{
						context.ErrorResult = new AuthenticationFailureResult("Missing device name", request);
						return;
					}

					context.Principal = identity;
				}
				else
				{
					context.ErrorResult = new AuthenticationFailureResult("Invalid credentials", request);
				}
			}
		}
        public HttpResponseMessage Update([FromBody] SettingsUpdateRequest settingsData)
        {
            if (string.IsNullOrWhiteSpace(settingsData.Data))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                Device device = RequestContext.GetDevice();
                Settings settings = database.CreateSettings(device, settingsData.Data);

                if (settings == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Error while saving the new settings");
                }
                return Request.CreateGoodReponse(new SettingsResponse(settings.SerializedSettings, settings.VersionNumber, settings.Date));
            }
        }
        public HttpResponseMessage CreateDevice([FromBody] DeviceCreateRequest device)
        {
            if (string.IsNullOrWhiteSpace(device.Name))
            {
                return Request.CreateBadRequestResponse();
            }

            User user = RequestContext.GetAuthenticatedUser();

            using (IDatabaseService database = new DatabaseService())
            {
                if (database.HasDevice(user, device.Name))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Conflict, "Device name already exists");
                }

                database.CreateDevice(user, device.Name);
                return Request.CreateResponse(HttpStatusCode.Created);
            }
        }
        public HttpResponseMessage Get([FromUri] string versionNumber)
        {
            long version;
            if (string.IsNullOrWhiteSpace(versionNumber) || !long.TryParse(versionNumber, out version))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                Device device = RequestContext.GetDevice();
                Settings settings = database.GetSettings(device, version);

                if (settings == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Version of settings not found");
                }
                return Request.CreateGoodReponse(new SettingsResponse(settings.SerializedSettings, settings.VersionNumber, settings.Date));
            }
        }
        public HttpResponseMessage Register([FromBody] UserRegisterRequest userInfo)
        {
            if (string.IsNullOrWhiteSpace(userInfo.Login) || string.IsNullOrWhiteSpace(userInfo.Email) || string.IsNullOrWhiteSpace(userInfo.Password))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                if (database.UserLoginExists(userInfo.Login))
                {
                    return Request.CreateCustomError(ERROR_CODE_LOGIN_EXISTS, ERROR_TEXT_LOGIN_EXISTS);
                }
                if (database.UserEmailExists(userInfo.Email))
                {
                    return Request.CreateCustomError(ERROR_CODE_EMAIL_EXISTS, ERROR_TEXT_EMAIL_EXISTS);
                }

                database.RegisterUser(userInfo.Login, userInfo.Email, userInfo.Password);
                return Request.CreateEmptyGoodReponse();
            }
        }
        public HttpResponseMessage All([FromUri] string versionNumber)
        {
            long version;
            if (!long.TryParse(versionNumber, out version))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                Device device = RequestContext.GetDevice();
                if (database.HasIndiagramVersion(device.UserId, version) && !database.IsVersionOpen(device.UserId, version))
                {
                    List<IndiagramForDevice> collection = database.GetIndiagrams(device, version);
                    List<IndiagramResponse> indiagrams = GetCollectionTree(collection);

                    return Request.CreateGoodReponse(indiagrams);
                }

                return Request.CreateErrorResponse(HttpStatusCode.NotFound, "indiagram version not found");
            }
        }
        public HttpResponseMessage Image([FromUri] string id)
        {
            long indiagramId;
            if (!long.TryParse(id, out indiagramId))
            {
                return Request.CreateBadRequestResponse();
            }

            Device device = RequestContext.GetDevice();
            using (IDatabaseService database = new DatabaseService())
            {
                IndiagramForDevice resultIndiagram = database.GetIndiagram(device, indiagramId);

                if (resultIndiagram == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Indiagram not found");
                }

                if (string.IsNullOrWhiteSpace(resultIndiagram.ImageHash))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No image file");
                }

                IStorageService storageService = new StorageService();
                byte[] content = storageService.DownloadImage(resultIndiagram.Id, resultIndiagram.Version);

                if (content == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, "Error while downloading file");
                }

                return Request.CreateGoodReponse(new FileDownloadResponse
                {
                    FileName = resultIndiagram.ImageFile,
                    Content = content
                });
            }
        }
        public HttpResponseMessage RenameDevice([FromBody] DeviceRenameRequest device)
        {
            if (string.IsNullOrWhiteSpace(device.ActualName) || string.IsNullOrWhiteSpace(device.NewName))
            {
                return Request.CreateBadRequestResponse();
            }

            User user = RequestContext.GetAuthenticatedUser();

            using (IDatabaseService database = new DatabaseService())
            {
                if (database.HasDevice(user, device.NewName))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Conflict, "Device name already exists");
                }

                if (!database.UpdateDevice(user, device.ActualName, device.NewName))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Device name not found");
                }
                return Request.CreateResponse(HttpStatusCode.Accepted);
            }
        }
        public HttpResponseMessage UpdateIndiagrams([FromBody] List<IndiagramRequest> request)
        {
            if (request == null || request.Any(x => string.IsNullOrEmpty(x.Text)))
            {
                return Request.CreateBadRequestResponse();
            }

            if (request.Count == 0)
            {
                return Request.CreateGoodReponse(new List<MappedIndiagramResponse>());
            }

            long version = request.First().Version;
            if (request.Any(x => x.Version != version))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                Device device = RequestContext.GetDevice();

                if (!database.HasIndiagramVersion(device.UserId, version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "version not found");
                }

                if (!database.CanPushInVersion(device.UserId, device.Id, version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Can not update in this version, version is closed or didn't created by this device");
                }

                bool hasError = false;
                Queue<IndiagramRequest> input = new Queue<IndiagramRequest>(request);
                List<IndiagramRequest> orderedRequests = new List<IndiagramRequest>();

                int noChangeCount = 0;
                Dictionary<long, long> mappedIds = new Dictionary<long, long>();
                while (input.Count > 0)
                {
                    IndiagramRequest item = input.Dequeue();
                    if (item.ParentId >= -1 || mappedIds.ContainsKey(item.ParentId))
                    {
                        noChangeCount = 0;
                        if (item.Id < -1)
                        {
                            mappedIds.Add(item.Id, 0);
                        }
                        orderedRequests.Add(item);
                    }
                    else
                    {
                        noChangeCount++;
                        if (noChangeCount == input.Count)
                        {
                            return Request.CreateBadRequestResponse("Cycle/missing indiagrams detected in collection");
                        }
                        input.Enqueue(item);
                    }
                }

                List<MappedIndiagramResponse> result = orderedRequests.Select(x =>
                {
                    IndiagramForDevice indiagram;

                    if (x.ParentId < 0)
                    {
                        x.ParentId = mappedIds[x.ParentId];
                    }

                    if (x.Id < 0)
                    {
                        indiagram = database.CreateIndiagram(device.UserId, device.Id, x);

                        mappedIds[x.Id] = indiagram.Id;
                    }
                    else
                    {
                        indiagram = database.UpdateIndiagram(device.UserId, device.Id, x);
                    }
                    if (indiagram == null)
                    {
                        hasError = true;
                        return null;
                    }
                    return new MappedIndiagramResponse
                    {
                        SentId = x.Id,
                        DatabaseId = indiagram.Id,
                        ParentId = indiagram.ParentId
                    };
                }).ToList();

                if (hasError)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "indiagram not found");
                }
                return Request.CreateGoodReponse(result);
            }
        }
        public HttpResponseMessage Indiagram([FromUri] string id)
        {
            long indiagramId;
            if (!long.TryParse(id, out indiagramId))
            {
                return Request.CreateBadRequestResponse();
            }

            Device device = RequestContext.GetDevice();
            using (IDatabaseService database = new DatabaseService())
            {
                IndiagramForDevice resultIndiagram = database.GetIndiagram(device, indiagramId);

                if (resultIndiagram == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Indiagram not found");
                }

                return Request.CreateGoodReponse(ToResponse(resultIndiagram));
            }
        }
        public HttpResponseMessage Versions([FromUri] string fromVersionNumber)
        {
            long fromVersion;
            if (!long.TryParse(fromVersionNumber, out fromVersion))
            {
                return Request.CreateBadRequestResponse();
            }

            User user = RequestContext.GetAuthenticatedUser();

            using (IDatabaseService database = new DatabaseService())
            {
                return Request.CreateGoodReponse(database.GetVersions(user.Id, fromVersion).Select(ToResponse));
            }
        }
        public HttpResponseMessage Indiagram([FromUri] string id, [FromUri] string versionNumber)
        {
            long indiagramId;
            long version;
            Device device = RequestContext.GetDevice();
            if (!long.TryParse(id, out indiagramId) || !long.TryParse(versionNumber, out version))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                if (!database.HasIndiagramVersion(device.UserId, version) || database.IsVersionOpen(device.UserId, version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Version not found");
                }

                IndiagramForDevice resultIndiagram = database.GetIndiagram(device, indiagramId, version);

                if (resultIndiagram == null)
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Indiagram not found");
                }

                return Request.CreateGoodReponse(ToResponse(resultIndiagram));
            }
        }
        public HttpResponseMessage UpdateIndiagram([FromBody] IndiagramRequest request)
        {
            if (request == null || string.IsNullOrWhiteSpace(request.Text))
            {
                return Request.CreateBadRequestResponse();
            }

            using (IDatabaseService database = new DatabaseService())
            {
                Device device = RequestContext.GetDevice();
                if (!database.HasIndiagramVersion(device.UserId, request.Version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.NotFound, "version not found");
                }

                if (!database.CanPushInVersion(device.UserId, device.Id, request.Version))
                {
                    return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Can not update in this version, version is closed or didn't created by this device");
                }

                if (request.Id < 0)
                {
                    IndiagramForDevice indiagram = database.CreateIndiagram(device.UserId, device.Id, request);
                    return Request.CreateGoodReponse(ToResponse(indiagram));
                }
                else
                {
                    //update
                    IndiagramForDevice indiagram = database.UpdateIndiagram(device.UserId, device.Id, request);

                    if (indiagram == null)
                    {
                        return Request.CreateErrorResponse(HttpStatusCode.NotFound, "indiagram not found");
                    }

                    return Request.CreateGoodReponse(ToResponse(indiagram));
                }

            }
        }