using Comal.Classes;
using InABox.Clients;
using InABox.Core;
using InABox.DynamicGrid;
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
using Org.BouncyCastle.Asn1.Mozilla;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace PRSDesktop.Panels.Products.Locations;
///
/// Interaction logic for StockHoldingRelocationWindow.xaml
///
public partial class StockHoldingRelocationWindow : Window, INotifyPropertyChanged
{
public StockHolding From { get; private init; }
public enum RelocationMode
{
Issue,
Transfer,
ReleaseAllocations
}
private RelocationMode _mode;
public RelocationMode Mode
{
get => _mode;
set
{
_mode = value;
UpdateMode();
}
}
public bool ShowHeader => ShowFrom || IsTargetEditable || IsJobEditable;
private bool _showFrom = true;
public bool ShowFrom
{
get => _showFrom;
set
{
_showFrom = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowHeader));
}
}
private bool _isTargetEditable = true;
public bool IsTargetEditable
{
get => _isTargetEditable;
set
{
_isTargetEditable = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowHeader));
}
}
private bool _isJobEditable = false;
public bool IsJobEditable
{
get => _isJobEditable;
set
{
_isJobEditable = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowHeader));
}
}
private StockLocation? _originalTarget;
public StockLocation? OriginalTarget
{
get => _originalTarget;
set
{
_originalTarget = value;
To = value;
}
}
private Job? _originalJob;
public Job? OriginalJob
{
get => _originalJob;
set
{
_originalJob = value;
Job = value;
}
}
private Job? _job;
public Job? Job
{
get => _job;
set
{
_job = value;
OnPropertyChanged();
OnPropertyChanged(nameof(CanSave));
OnPropertyChanged($"{nameof(Job)}.{nameof(Job.JobNumber)}");
OnPropertyChanged($"{nameof(Job)}.{nameof(Job.Name)}");
UpdateMode();
}
}
private StockLocation? _to;
public StockLocation? To
{
get => _to;
set
{
_to = value;
OnPropertyChanged();
OnPropertyChanged(nameof(CanSave));
OnPropertyChanged($"{nameof(To)}.{nameof(To.Code)}");
OnPropertyChanged($"{nameof(To)}.{nameof(To.Description)}");
}
}
private bool _requireChangeTarget = false;
///
/// Require that the target location be changed before allowing the "Save" button to be clicked.
///
public bool RequireChangeTarget
{
get => _requireChangeTarget;
set
{
_requireChangeTarget = value;
OnPropertyChanged();
OnPropertyChanged(nameof(CanSave));
}
}
public bool CanSave
{
get
{
if(Grid.TotalIssued <= 0)
{
return false;
}
if(IsTargetEditable && (To?.ID ?? Guid.Empty) == Guid.Empty)
{
return false;
}
if (RequireChangeTarget)
{
if(IsTargetEditable && IsJobEditable)
{
return (To?.ID ?? Guid.Empty) != (OriginalTarget?.ID ?? Guid.Empty)
|| (Job?.ID ?? Guid.Empty) != (OriginalJob?.ID ?? Guid.Empty);
}
else if (IsTargetEditable)
{
return (To?.ID ?? Guid.Empty) != (OriginalTarget?.ID ?? Guid.Empty);
}
else if (IsJobEditable)
{
return (Job?.ID ?? Guid.Empty) != (OriginalJob?.ID ?? Guid.Empty);
}
}
return true;
}
}
public StockHoldingRelocationWindow(StockHolding from, IEnumerable items, RelocationMode mode)
{
Client.EnsureColumns(from, Columns.None().Add(x => x.Location.Code));
From = from;
InitializeComponent();
SetRequisitionItems(items);
Mode = mode;
}
private void UpdateMode()
{
if(Mode == RelocationMode.Issue)
{
var jobID = Job?.ID ?? Guid.Empty;
foreach(var item in Grid.Items)
{
if(item.JRI.ID != Guid.Empty && item.JRI.Job.ID != jobID)
{
item.Editable = false;
item.Issued = 0;
}
else
{
item.Editable = true;
}
}
Title = "Issue Items";
IsJobEditable = true;
IsTargetEditable = false;
ShowFrom = true;
}
else if(Mode == RelocationMode.Transfer)
{
foreach(var item in Grid.Items)
{
item.Editable = item.JRI.ID == Guid.Empty || Security.IsAllowed();
}
IsJobEditable = true;
IsTargetEditable = true;
ShowFrom = false;
RequireChangeTarget = true;
Title = "Transfer Stock";
}
else if(Mode == RelocationMode.ReleaseAllocations)
{
ShowFrom = false;
IsTargetEditable = false;
IsJobEditable = false;
Title = "Release Stock";
}
}
private void Grid_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == nameof(Grid.TotalIssued))
{
OnPropertyChanged(nameof(CanSave));
}
}
public void SetRequisitionItems(IEnumerable items)
{
var rItems = items.AsIList();
var rIDs = rItems.Select(x => x.ID).Where(x => x != Guid.Empty).ToArray();
var quantities = Client.Query(
StockHolding.GetFilter(From)
.Combine(new Filter(x => x.JobRequisitionItem.ID).InList(rIDs)),
Columns.None().Add(x => x.Units).Add(x => x.JobRequisitionItem.ID))
.ToObjects().GroupBy(x => x.JobRequisitionItem.ID).ToDictionary(x => x.Key, x => x.Sum(x => x.Units));
var requidItems = new List();
var newItems = new List();
foreach(var item in rItems)
{
var qty = item.ID != Guid.Empty ? quantities.GetValueOrDefault(item.ID) : item.Qty;
if(item.ID != Guid.Empty && qty <= 0)
{
// We can't do anything with this; it shouldn't be shown.
continue;
}
var newItem = new StockHoldingRelocationItem
{
Issued = 0,
Quantity = qty,
MaxValue = item.ID == Guid.Empty ? double.MaxValue : qty,
Text = item.ID == Guid.Empty
? "Unrequisitioned Items"
: $"{item.Job.JobNumber}: #{item.Requisition.Number} ({item.Requisition.Description})",
JRI = item
};
if(item.ID == Guid.Empty)
{
newItems.Add(newItem);
}
else
{
requidItems.Add(newItem);
}
}
int i = 1;
foreach(var item in requidItems)
{
item.ItemNumber = $"{i}. ";
newItems.Add(item);
++i;
}
Grid.Items = newItems;
Grid.Refresh(true, true);
}
public Dictionary GetQuantities()
{
return Grid.Items.ToDictionary(x => x.JRI.ID, x => x.Issued);
}
public StockLocation GetTargetLocation()
{
return To ?? new StockLocation();
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#region Target Location
public static StockLocation? LookupLocation(string? column = null, string? value = null)
{
var grid = new MultiSelectDialog(
LookupFactory.DefineFilter(),
Columns.None().Add(x => x.ID).Add(x => x.Code).Add(x => x.Description),
multiselect: false);
if (grid.ShowDialog(column, value))
{
return grid.Data().Rows.First().ToObject();
}
else
{
return null;
}
}
private bool DoLookupLocation(string? column, string? value)
{
if(LookupLocation(column, value) is StockLocation location)
{
To = location;
return true;
}
else
{
return false;
}
}
private void ToBox_LostFocus(object sender, RoutedEventArgs e)
{
DoSearchLocation();
}
private void ToButton_Click(object sender, RoutedEventArgs e)
{
DoLookupLocation(null, null);
}
private void DoSearchLocation()
{
if (ToBox.Text.IsNullOrWhiteSpace() || ToBox.Text == To?.Code)
{
To = null;
return;
}
var location = Client.Query(
new Filter(x => x.Code).IsEqualTo(ToBox.Text),
Columns.None().Add(x => x.ID).Add(x => x.Code).Add(x => x.Description))
.ToObjects().FirstOrDefault();
if(location is not null)
{
To = location;
}
else
{
if(!DoLookupLocation(nameof(To.Code), ToBox.Text))
{
To = null;
}
}
}
private void ToBox_OnKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
DoSearchLocation();
}
#endregion
#region Job
private bool DoLookupJob(string? column, string? value)
{
var grid = new MultiSelectDialog(
LookupFactory.DefineFilter(),
Columns.None().Add(x => x.ID).Add(x => x.JobNumber).Add(x => x.Name),
multiselect: false);
if (grid.ShowDialog(column, value))
{
Job = grid.Data().Rows.First().ToObject();
return true;
}
else
{
return false;
}
}
private void JobBox_LostFocus(object sender, RoutedEventArgs e)
{
DoSearchJob();
}
private void JobButton_Click(object sender, RoutedEventArgs e)
{
DoLookupJob(null, null);
}
private void DoSearchJob()
{
if (JobBox.Text.IsNullOrWhiteSpace() || JobBox.Text == To?.Code)
{
Job = null;
return;
}
var job = Client.Query(
new Filter(x => x.JobNumber).IsEqualTo(JobBox.Text),
Columns.None().Add(x => x.ID).Add(x => x.JobNumber).Add(x => x.Name))
.ToObjects().FirstOrDefault();
if(job is not null)
{
Job = job;
}
else
{
if(!DoLookupJob(nameof(Job.JobNumber), JobBox.Text))
{
Job = null;
}
}
}
private void JobBox_OnKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
DoSearchJob();
}
#endregion
private void OKButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = true;
Close();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
}