protected void btnOK_Clicked(object o, EventArgs args)
        {
            if (!Validate())
            {
                return;
            }

            OperationNumberingInfo.Update(allStartNumbers);
            dlgEditDocumentNumbersPerLocation.Respond(ResponseType.Ok);
        }
        private void SelectDocumentType(OperationNumberingInfo operation)
        {
            SelectLocation(operation.LocationId);

            BindingListModel <OperationNumberingInfo> modelNumbers = (BindingListModel <OperationNumberingInfo>)gridDocumentNumbers.Model;
            int index = modelNumbers.FindIndex(o => o.OperationType == operation.OperationType);

            gridDocumentNumbers.Selection.Clear();
            gridDocumentNumbers.Selection.Select(index);
            gridDocumentNumbers.ScrollToV(index);
        }
        private bool Validate()
        {
            if (hasEmptyRange)
            {
                MessageError.ShowDialog(emptyRangeMessage);
                return(false);
            }

            var  maxId      = Operation.GetMaxId();
            bool userWarned = false;

            for (int i = allStartNumbersPerLocation.Count - 1; i >= 0; i--)
            {
                foreach (OperationNumberingInfo numberingInfo in allStartNumbersPerLocation[i].Value)
                {
                    long endRange = maxId;
                    OperationNumberingInfo nextInfo = null;
                    if (i + 1 < allStartNumbersPerLocation.Count)
                    {
                        nextInfo = allStartNumbersPerLocation [i + 1].Value.FirstOrDefault(n => n.OperationType == numberingInfo.OperationType);
                        if (nextInfo != null)
                        {
                            endRange = nextInfo.StartNumber - 2;
                        }
                    }

                    long rangeSize = Math.Max(endRange - numberingInfo.StartNumber, 0);
                    if (rangeSize < OperationNumberingInfo.MINIMAL_NUMBERS_PER_LOCATION)
                    {
                        MessageError.ShowDialog(GetShortRangeWarning(numberingInfo, nextInfo, true, maxId), ErrorSeverity.Error);
                        SelectDocumentType(numberingInfo);
                        return(false);
                    }

                    if (userWarned || rangeSize >= OperationNumberingInfo.RECOMMENDED_NUMBERS_PER_LOCATION - 2)
                    {
                        continue;
                    }

                    if (Message.ShowDialog(Translator.GetString("Document Numbers per Location"), string.Empty,
                                           string.Format(GetShortRangeWarning(numberingInfo, nextInfo, false, maxId), OperationNumberingInfo.RECOMMENDED_NUMBERS_PER_LOCATION), "Icons.Warning32.png",
                                           MessageButtons.YesNo) == ResponseType.No)
                    {
                        SelectDocumentType(numberingInfo);
                        return(false);
                    }
                    userWarned = true;
                }
            }
            return(true);
        }
        private string GetShortRangeWarning(OperationNumberingInfo operation, OperationNumberingInfo nextOperation, bool minimal, long maxId)
        {
            BindingListModel <Location> locations = (BindingListModel <Location>)gridLocations.Model;
            string currentLocation = locations.Find(l => l.Id == operation.LocationId).Name;
            string nextLocation    = string.Empty;

            string message;

            if (nextOperation != null)
            {
                if (minimal)
                {
                    message = Translator.GetString("The numbers between the start numbers for locations \"{0}\" and \"{1}\" " +
                                                   "for operations of type \"{2}\" are less than the minimal value of {3}.");
                }
                else
                {
                    message = Translator.GetString("The numbers between the start numbers for locations \"{0}\" and \"{1}\" (possibly other ranges too) " +
                                                   "for operations of type \"{2}\" are less than the recommended value of {3}. " +
                                                   "Are you sure you want to continue?");
                }

                nextLocation = locations.Find(l => l.Id == nextOperation.LocationId).Name;
            }
            else
            {
                if (minimal)
                {
                    message = Translator.GetString("The numbers between the start number for location \"{0}\" and the maximal operation number {4} " +
                                                   "for operations of type \"{2}\" are less than the minimal value of {3}.");
                }
                else
                {
                    message = Translator.GetString("The numbers between the start number for location \"{0}\" and the maximal operation number {4} (possibly other ranges too) " +
                                                   "for operations of type \"{2}\" are less than the recommended value of {3}. " +
                                                   "Are you sure you want to continue?");
                }
            }

            string operationType = Translator.GetOperationTypeGlobalName(operation.OperationType);

            return(string.Format(message,
                                 currentLocation,
                                 nextLocation,
                                 operationType,
                                 minimal ? OperationNumberingInfo.MINIMAL_NUMBERS_PER_LOCATION : OperationNumberingInfo.RECOMMENDED_NUMBERS_PER_LOCATION,
                                 maxId.ToString("N", formatBigNumber)));
        }
        private bool UpdateDocumentsUsage(long?maxId = null)
        {
            if (numbersUsagePerLocation == null ||
                numbersUsageStarts == null)
            {
                return(false);
            }

            if (maxId == null)
            {
                maxId = Operation.GetMaxId();
            }

            hasEmptyRange = false;

            for (int i = 0; i < allStartNumbersPerLocation.Count; i++)
            {
                foreach (OperationNumberingInfo numberingInfo in allStartNumbersPerLocation[i].Value)
                {
                    long endNumber = maxId.Value;
                    long endRange  = endNumber;
                    if (i + 1 < allStartNumbersPerLocation.Count)
                    {
                        OperationNumberingInfo nextInfo = allStartNumbersPerLocation [i + 1].Value.FirstOrDefault(n => n.OperationType == numberingInfo.OperationType);
                        if (nextInfo != null)
                        {
                            endRange = nextInfo.StartNumber - 1;
                            if (nextInfo.StartNumber > 0)
                            {
                                endNumber = nextInfo.StartNumber - 1;
                            }
                        }
                    }

                    long usedNumbers            = 0;
                    long startNumber            = numberingInfo.StartNumber + 1;
                    OperationNumbersUsage usage = numbersUsagePerLocation.FirstOrDefault(n => numberingInfo.LocationId == n.LocationId && numberingInfo.OperationType == n.OperationType);
                    if (usage != null)
                    {
                        usedNumbers = usage.UsedNumbers;
                        startNumber = Math.Max(startNumber, usage.LastUsedNumber);
                    }

                    ObjectsContainer <OperationType, long> firtNextNumber = numbersUsageStarts.FirstOrDefault(n => numberingInfo.StartNumber < n.Value2 && numberingInfo.OperationType == n.Value1);
                    if (firtNextNumber != null)
                    {
                        endNumber = Math.Min(endNumber, firtNextNumber.Value2 - 1);
                    }

                    double numbersLeft = Math.Max(endNumber - startNumber, 0);
                    if (numbersLeft < OperationNumberingInfo.MINIMAL_NUMBERS_PER_LOCATION)
                    {
                        hasEmptyRange = true;
                    }

                    long rangeSize = Math.Max(endRange - numberingInfo.StartNumber, 0);
                    if (rangeSize == 0)
                    {
                        MessageError.ShowDialog(string.Format(Translator.GetString("The selected numbers parameters are not valid! Please select ranges which will generate document numbers lower than {0}."), maxId.Value.ToString("N", formatBigNumber)));
                        throw new ArgumentOutOfRangeException();
                    }

                    numberingInfo.Usage            = (rangeSize - numbersLeft) / rangeSize;
                    numberingInfo.UsageDescription = string.Format(Translator.GetString("{0} used, {1} left"),
                                                                   usedNumbers.ToString("N", formatBigNumber),
                                                                   numbersLeft.ToString("N", formatBigNumber));
                }
            }

            frmMessage.Visible = hasEmptyRange;

            IListModel model = gridDocumentNumbers.Model;

            gridDocumentNumbers.Model = null;
            gridDocumentNumbers.Model = model;
            return(true);
        }
        private void InitializeLocationsGrid()
        {
            gridLocations = new ListView
            {
                Name                = "gridLocations",
                WidthRequest        = 250,
                HeightRequest       = 400,
                AllowMultipleSelect = false
            };
            gridLocations.Selection.Changed += Selection_Changed;

            gridLocations.ColumnController = new ColumnController
            {
                new Column(Translator.GetString("Location"), "Name", 1, "Name")
            };

            scwLocations.Add(gridLocations);
            gridLocations.Show();

            allLocations = Location.GetAll();

            bool recreated = false;
            bool retry;

            do
            {
                retry           = false;
                allStartNumbers = OperationNumberingInfo.Get();
                if (allStartNumbers.Length == 0)
                {
                    OperationNumberingInfo.Create();
                    recreated       = true;
                    allStartNumbers = OperationNumberingInfo.Get();
                }
                allStartNumbersPerLocation.Clear();

                foreach (Location location in allLocations)
                {
                    Location l = location;
                    List <OperationNumberingInfo> operations = allStartNumbers.Where(o => o.LocationId == l.Id).ToList();
                    if (operations.Count == 0 && !recreated)
                    {
                        OperationNumberingInfo.Create();
                        retry     = true;
                        recreated = true;
                        break;
                    }

                    foreach (var info in operations)
                    {
                        info.UsageDescription = Translator.GetString("Calculating...");
                    }

                    allStartNumbersPerLocation.Add(new KeyValuePair <long, BindingListModel <OperationNumberingInfo> > (location.Id,
                                                                                                                        new BindingListModel <OperationNumberingInfo> (operations)));
                }
            } while (retry);

            DataHelper.FireAndForget(() =>
            {
                numbersUsagePerLocation = OperationNumbersUsage.Get();
                numbersUsageStarts      = OperationNumbersUsage.GetUsagesStarts();
                Timeout.Add(0, () =>
                {
                    try {
                        UpdateDocumentsUsage();
                    } catch (ArgumentOutOfRangeException) { }
                    return(false);
                });
            });

            allStartNumbersPerLocation = allStartNumbersPerLocation.OrderBy(p => p.Value.Min(o => o.StartNumber)).ToList();
            // Use a model with natural order by the operation number intervals
            gridLocations.Model = new BindingListModel <Location> (allStartNumbersPerLocation.Select(d => allLocations.Find(p => p.Id == d.Key)));
            lblCurrentLocationsValue.SetText(allLocations.Count.ToString("N", formatBigNumber));

            if (gridLocations.Model.Count <= 0)
            {
                return;
            }

            gridLocations.FocusRow(0);
            gridLocations.Selection.Select(0);
            gridLocations.ScrollToV(0);
        }