using Comal.Classes;
using InABox.Clients;
using InABox.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XF.Material.Forms.UI.Dialogs;
namespace PRS.Mobile
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class RecTrans
    {
        #region Fields + Constructor + Loading
        /// 
        /// The list of available holdings to take from.
        ///  
        private List issuingHoldings = new List();
        /// 
        /// The list of items on the right hand side, representing the new locations.
        ///  
        private List receivingHoldings = new List();
        /// 
        /// The list of items that have been taken; the originals.
        ///  
        private List originalHoldings = new List();
        // We can either be receiving to a job or a location, so only one of these should be non-empty at a time.
        private Job ReceivingJob = new Job();
        private StockLocation ReceivingStockLocation = new StockLocation();
        // We can be issuing from just locations (can't issue from a job).
        private StockLocation IssuingStockLocation = new StockLocation();
        private ProductStyle DefaultStyle = new ProductStyle();
        private ProductStyle PreviousStyle = new ProductStyle();
        private bool bTapping = false;
        private double frameHeight = 80;
        private List favourites = new List();
        private readonly StockMovementBatchType BatchType;
        private string DeviceType = "";
        public RecTrans(StockMovementBatchType batchType, string issuingGuidString = "")
        {
            InitializeComponent();
            Title = BatchType == StockMovementBatchType.Issue
                ? "Issue Stock"
                : "Transfer Stock";
            BatchType = batchType;
            var idiom = DeviceInfo.Idiom;
            if (idiom.Equals(DeviceIdiom.Tablet))
            {
                DeviceType = "Tablet";
            }
            //DisplayAlert("Instructions", "1. Select Issuing Location or use default (incoming stores)." + System.Environment.NewLine
            //    + System.Environment.NewLine
            //    + "2. Select Receiving Location or Job to Issue to." + System.Environment.NewLine
            //    + System.Environment.NewLine
            //    + "3. Tap items to transfer." + System.Environment.NewLine
            //    + System.Environment.NewLine
            //    + "4. Save with photos + notes." + System.Environment.NewLine
            //    + System.Environment.NewLine
            //    + "Note: Exiting loses unsaved work", "OK");
            IssuingStockLocation.PropertyChanged += IssuingStockLocation_PropertyChanged;
            ReceivingStockLocation.PropertyChanged += ReceivingStockLocation_PropertyChanged;
            LoadFavourites();
            ShowHideButtonsBasedOnType();
            LoadFromProductSearch(issuingGuidString);
        }
        private void LoadFromProductSearch(string issuingGuidString)
        {
            if (!string.IsNullOrWhiteSpace(issuingGuidString))
            {
                try
                {
                    Guid issuingLocationID = Guid.Parse(issuingGuidString);
                    CoreTable table = new Client().Query(new Filter(x => x.ID).IsEqualTo(issuingLocationID),
                        new Columns(x => x.ID, x => x.Code, x => x.Description)
                        );
                    if (table.Rows.Any())
                    {
                        List list = table.Rows.First().Values;
                        IssuingStockLocation.ID = Guid.Parse(list[0].ToString());
                        IssuingStockLocation.Code = list[1].ToString();
                        IssuingStockLocation.Description = list[2].ToString();
                    }
                    Filter filter = new Filter(x => x.Location.ID).IsEqualTo(issuingLocationID);
                    LoadIncomingListData(filter);
                }
                catch { }
            }
        }
        private void ShowHideButtonsBasedOnType()
        {
            if (BatchType == StockMovementBatchType.Issue)
            {
                receivingFavouriteBtn1.IsEnabled = false;
                receivingFavouriteBtn2.IsEnabled = false;
                receivingFavouriteBtn3.IsEnabled = false;
                chooseReceivingLocationBtn.IsVisible = false;
                receivingLocationLbl.Text = "Choose Job";
                //titleLbl.Text = "Issue to Job";
            }
            else if (BatchType == StockMovementBatchType.Transfer)
            {
                chooseJobBtn.IsVisible = false;
            }
        }
        #endregion
        #region Issuing Button Presses
        private async void ChooseIssuingLocationBtn_Clicked(object sender, EventArgs e)
        {
            CollapseExpanderOnButtonPress();
            if (receivingHoldings.Count > 0)
            {
                PromptResetScreen();
            }
            else
            {
                ChooseIssuingLocation();
            }
        }
        private void IssuingFavourite_Clicked(object sender, EventArgs e)
        {
            string chosenFavourite = (sender as Button).Text;
            CollapseExpanderOnButtonPress();
            if (receivingHoldings.Count > 0)
            {
                PromptResetScreen(chosenFavourite);
            }
            else
            {
                IssuingFavouriteChosen(chosenFavourite);
            }
        }
        #endregion
        #region Issuing Location Methods
        private void ChooseIssuingLocation()
        {
            StockLocationSelectionPage page = new StockLocationSelectionPage();
            page.OnLocationSelected += (s) =>
            {
                if (ReceivingStockLocation.ID == s.ID)
                    return;
                IssuingStockLocation.ID = s.ID;
                IssuingStockLocation.Code = s.Code;
                IssuingStockLocation.Description = s.Description;
                Filter newIssuingFilter = new Filter(x => x.Location.ID).IsEqualTo(IssuingStockLocation.ID);
                issuingHoldings.Clear();
                receivingHoldings.Clear();
                LoadIncomingListData(newIssuingFilter);
                Device.BeginInvokeOnMainThread(() =>
                {
                });
            };
            Navigation.PushAsync(page);
        }
        private async void IssuingFavouriteChosen(string chosenFavourite)
        {
            ClearLists();
            StockLocation location = favourites.Find(x => x.Code.Equals(chosenFavourite));
            IssuingStockLocation.ID = location.ID;
            IssuingStockLocation.Code = location.Code;
            IssuingStockLocation.Description = location.Description;
            Filter filter = new Filter(x => x.Location.ID).IsEqualTo(IssuingStockLocation.ID);
            LoadIncomingListData(filter);
        }
        #endregion
        #region Receiving Button Presses
        private async void ChooseReceivingLocationBtn_Clicked(object sender, EventArgs e)
        {
            string chosenOption = await DisplayActionSheet("Choose an Option", "Cancel", null, "New Location", "Existing Location");
            switch (chosenOption)
            {
                case "Cancel":
                    return;
                case "New Location":
                    ChooseNewLocation();
                    CollapseExpanderOnButtonPress();
                    break;
                case "Existing Location":
                    ChooseReceivingLocation();
                    CollapseExpanderOnButtonPress();
                    break;
                default:
                    return;
            }
        }
        private void JobBtn_Clicked(object sender, EventArgs e)
        {
            ChooseJob();
            CollapseExpanderOnButtonPress();
        }
        private void ReceivingFavourite_Clicked(object sender, EventArgs e)
        {
            CollapseExpanderOnButtonPress();
            string chosenFavourite = (sender as Button).Text;
            ReceivingFavouriteChosen(chosenFavourite);
        }
        #endregion
        #region Receiving Location Methods
        private void IssueToLocation(StockLocation location)
        {
            if (location.ID == IssuingStockLocation.ID)
                return;
            // Clear the job, because we're going to a location now.
            ReceivingJob = new Job();
            ReceivingStockLocation = location;
            LoadDefaultStyle();
            Device.BeginInvokeOnMainThread(() =>
            {
                //titleLbl.Text = "Transfer Stock";
                receivingLocationLbl.Text = ReceivingStockLocation.Description;
            });
        }
        private void IssueToJob(JobShell job)
        {
            // Clear the location, because we're going to a job now.
            ReceivingStockLocation = new StockLocation();
            ReceivingJob.ID = job.ID;
            ReceivingJob.Name = job.Name;
            ReceivingJob.JobNumber = job.JobNumber;
            Device.BeginInvokeOnMainThread(() =>
            {
                //titleLbl.Text = "Issue to Job";
                receivingLocationLbl.Text = ReceivingJob.JobNumber;
            });
        }
        private void ReceivingFavouriteChosen(string chosenFavourite)
        {
            StockLocation location = favourites.Find(x => x.Code.Equals(chosenFavourite));
            IssueToLocation(location);
        }
        private void ChooseReceivingLocation()
        {
            StockLocationSelectionPage page = new StockLocationSelectionPage();
            page.OnLocationSelected += (s) =>
            {
                IssueToLocation(new StockLocation
                {
                    ID = s.ID,
                    Code = s.Code,
                    Description = s.Description
                });
            };
            Navigation.PushAsync(page);
        }
        private void ChooseNewLocation()
        {
            try
            {
                StockLocation location = new StockLocation();
                location.Active = true;
                location.Warehouse.ID = Guid.Parse("b6249c4a-a834-4927-a42c-87a07895d6bd"); //EXTRUSIONS
                location.Warehouse.Description = "Extrusions";
                location.Warehouse.Code = "EXTRUSIONS";
                location.Area.Warehouse.ID = Guid.Parse("b6249c4a-a834-4927-a42c-87a07895d6bd"); //EXTRUSIONS
                location.Area.Warehouse.Description = "Extrusions";
                location.Area.ID = Guid.Parse("fa02ecd8-e642-49aa-98b5-c04d7ea0f4eb"); //Rack FLOOR
                location.Area.Description = "Rack FLOOR";
                location.Area.Code = "FLOOR";
                LocationDetailsPage locationDetailsPage = new LocationDetailsPage(location);
                locationDetailsPage.OnSave += (o, loc) =>
                {
                    if (String.IsNullOrWhiteSpace(loc.Code))
                    {
                        MaterialDialog.Instance.AlertAsync(message: "Code may not be blank!");
                        return false;
                    }
                    if (String.IsNullOrWhiteSpace(loc.Description))
                    {
                        MaterialDialog.Instance.AlertAsync(message: "Description may not be blank!");
                        return false;
                    }
                    if (loc.Area.ID == Guid.Empty)
                    {
                        MaterialDialog.Instance.AlertAsync(message: "Area may not be blank!");
                        return false;
                    }
                    CoreTable others = new Client().Query(
                        new Filter(x => x.Code).IsEqualTo(loc.Code).And(x => x.ID).IsNotEqualTo(loc.ID),
                        new Columns(x => x.ID)
                    );
                    if (others.Rows.Any())
                    {
                        MaterialDialog.Instance.AlertAsync(message: "Location Code already exists!");
                        return false;
                    }
                    try
                    {
                        new Client().Save(loc, "Created Location");
                        IssueToLocation(loc);
                    }
                    catch (Exception err)
                    {
                        MaterialDialog.Instance.AlertAsync(message: "Unable to save Location\n" + err.Message);
                        return false;
                    }
                    return true;
                };
                Navigation.PushAsync(locationDetailsPage);
            }
            catch { }
        }
        private void ChooseJob()
        {
            var jobSelectionPage = new JobSelectionPage(
                (job) =>
                {
                    IssueToJob(job);
                });
            Navigation.PushAsync(jobSelectionPage);
        }
        #endregion
        #region Lists Tapped
        private void IssuingListView_Tapped(object sender, EventArgs e)
        {
            if (ReceivingStockLocation.ID == Guid.Empty && ReceivingJob.ID == Guid.Empty)
                return;
            if (bTapping)
                return;
            bTapping = true;
            var originalShell = issuingListView.SelectedItem as StockHoldingShell_Old;
            var job = new Job();
            if (ReceivingStockLocation.Job.ID != Guid.Empty)
            {
                job = new Job
                {
                    ID = ReceivingStockLocation.Job.ID,
                    JobNumber = ReceivingStockLocation.Job.JobNumber,
                    Name = ReceivingStockLocation.Job.Name
                };
            }
            var popup = new RecTransferPopup(DuplicateShell(originalShell), job, ReceivingJob);
            popup.OnRecTransferItemAccepted += () =>
            {
                if (popup.Shell.Units == originalShell.Units)
                {
                    // Remove from left-hand list, because we can't select any more of this.
                    issuingHoldings.Remove(originalShell);
                    receivingHoldings.Add(popup.Shell);
                    RefreshLists();
                }
                else if (originalShell.Units > popup.Shell.Units)
                {
                    originalShell.Units -= popup.Shell.Units;
                    originalShell.DisplayUnits = "Units: " + originalShell.Units;
                    receivingHoldings.Add(popup.Shell);
                    //popup shell with new properties is added to receiving list
                    RefreshLists();
                }
                originalHoldings.Add(originalShell);
                PreviousStyle.ID = popup.Shell.StyleID;
                PreviousStyle.Code = popup.Shell.StyleCode;
                PreviousStyle.Description = popup.Shell.Finish;
                bTapping = false;
            };
            popup.OnRecTransferPopupBackButtonPressed += () =>
            {
                bTapping = false;
                RefreshLists();
            };
            Navigation.PushAsync(popup);
        }
        private void ReceivingListView_Tapped(object sender, EventArgs e)
        {
            StockHoldingShell_Old shell = receivingListView.SelectedItem as StockHoldingShell_Old;
            RemoveHoldingFromBatch(shell);
        }
        /// 
        /// Remove from the batch being transferred, and put back in the issuing list.
        ///  
        ///  
        private void RemoveHoldingFromBatch(StockHoldingShell_Old shell)
        {
            receivingHoldings.Remove(shell);
            if (issuingHoldings.Find(x => x.ID.Equals(shell.ID)) != null)
            {
                var existingHolding = issuingHoldings.Find(x => x.ID.Equals(shell.ID));
                existingHolding.Units += shell.Units;
                existingHolding.DisplayUnits = "Units: " + existingHolding.Units;
            }
            else
            {
                issuingHoldings.Add(shell);
            }
            RefreshLists();
        }
        #endregion
        #region Refresh Reset Screen
        private async void PromptResetScreen(string chosenFavourite = "")
        {
            string chosenOption = await DisplayActionSheet("This will remove items in current batch", "Cancel", null, "Confirm");
            switch (chosenOption)
            {
                case "Confirm":
                    ClearLists();
                    if (!string.IsNullOrWhiteSpace(chosenFavourite))
                        IssuingFavouriteChosen(chosenFavourite);
                    else
                        ChooseIssuingLocation();
                    break;
                default:
                    return;
            }
        }
        private void ClearLists()
        {
            issuingHoldings.Clear();
            receivingHoldings.Clear();
            RefreshLists();
        }
        private void RefreshLists()
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                issuingListView.ItemsSource = null;
                issuingListView.ItemsSource = issuingHoldings;
                receivingListView.ItemsSource = null;
                receivingListView.ItemsSource = receivingHoldings;
                issuingLocationCountLbl.Text = "Items: " + issuingHoldings.Count();
                receivingCountLbl.Text = "Items in Batch: " + receivingHoldings.Count();
                searchEnt.Text = "";
                if (receivingHoldings.Count > 0)
                {
                    Save.IsEnabled = true;
                }
                else
                {
                    Save.IsEnabled = false;
                }
            });
        }
        #endregion      
        #region Search
        private void SearchEnt_Changed(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(searchEnt.Text))
            {
                issuingListView.ItemsSource = issuingHoldings;
            }
            else
            {
                RunSearch();
            }
        }
        private void RunSearch()
        {
            issuingListView.ItemsSource = issuingHoldings.Where
                        (x => x.Code.Contains(searchEnt.Text) || x.Code.Contains(UpperCaseFirst(searchEnt.Text)) || x.Code.Contains(searchEnt.Text.ToLower()) || x.Code.Contains(searchEnt.Text.ToUpper())
                        || x.Name.Contains(searchEnt.Text) || x.Name.Contains(UpperCaseFirst(searchEnt.Text)) || x.Name.Contains(searchEnt.Text.ToLower()) || x.Name.Contains(searchEnt.Text.ToUpper())
                        || x.Finish.Contains(searchEnt.Text) || x.Finish.Contains(UpperCaseFirst(searchEnt.Text)) || x.Finish.Contains(searchEnt.Text.ToLower()) || x.Finish.Contains(searchEnt.Text.ToUpper())
                        );
        }
        static String UpperCaseFirst(string s)
        {
            char[] a = s.ToCharArray();
            a[0] = char.ToUpper(a[0]);
            return new string(a);
        }
        #endregion
        #region Utils
        private async void LoadIncomingListData(Filter filter)
        {
            using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Loading"))
            {
                CoreTable table = DoQuery(filter);
                while (table == null)
                    table = DoQuery(filter);
                if (table.Rows.Any())
                {
                    foreach (CoreRow row in table.Rows)
                    {
                        StockHoldingShell_Old shell = new StockHoldingShell_Old();
                        shell.ID = row.Get(x => x.Location.ID).ToString()
                        + row.Get(x => x.Product.ID).ToString()
                        + row.Get(x => x.Job.ID).ToString()
                        + row.Get(x => x.Style.ID).ToString()
                        + row.Get(x => x.Dimensions.UnitSize);
                        shell.Code = row.Get(x => x.Product.Code);
                        shell.Name = row.Get(x => x.Product.Name);
                        shell.Finish = row.Get(x => x.Style.Description);
                        shell.StyleName = "Finish: " + shell.Finish;
                        shell.DimensionsUnitSize = row.Get(x => x.Dimensions.UnitSize);
                        shell.Units = row.Get(x => x.Units);
                        shell.DisplaySize = "Size: " + shell.DimensionsUnitSize;
                        shell.DisplayUnits = "Units: " + shell.Units;
                        shell.JobID = row.Get(x => x.Job.ID);
                        shell.JobName = row.Get(x => x.Job.Name);
                        shell.JobNumber = row.Get(x => x.Job.JobNumber);
                        shell.DisplayJob = "Job: " + shell.JobNumber;
                        shell.StyleID = row.Get(x => x.Style.ID);
                        shell.StyleCode = row.Get(x => x.Style.Code);
                        shell.ProductID = row.Get(x => x.Product.ID);
                        shell.ImageID = row.Get(x => x.Product.Image.ID);
                        shell.DimensionsUnitID = row.Get(x => x.Dimensions.Unit.ID);
                        shell.DimensionsQuantity = row.Get(x => x.Dimensions.Quantity);
                        shell.DimensionsLength = row.Get(x => x.Dimensions.Length);
                        shell.DimensionsWidth = row.Get(x => x.Dimensions.Width);
                        shell.DimensionsHeight = row.Get(x => x.Dimensions.Height);
                        shell.DimensionsWeight = row.Get(x => x.Dimensions.Weight);
                        shell.DimensionsValue = row.Get(x => x.Dimensions.Value);
                        shell.DimensionsHasHeight = row.Get(x => x.Dimensions.Unit.HasHeight);
                        shell.DimensionsHasLength = row.Get(x => x.Dimensions.Unit.HasLength);
                        shell.DimensionsHasWidth = row.Get(x => x.Dimensions.Unit.HasWidth);
                        shell.DimensionsHasWeight = row.Get(x => x.Dimensions.Unit.HasWeight);
                        shell.DimensionsHasQuantity = row.Get(x => x.Dimensions.Unit.HasQuantity);
                        shell.DimensionsUnitFormula = row.Get(x => x.Dimensions.Unit.Formula);
                        shell.DimensionsUnitFormat = row.Get(x => x.Dimensions.Unit.Format);
                        shell.DimensionsUnitCode = row.Get(x => x.Dimensions.Unit.Code);
                        shell.DimensionsUnitDescription = row.Get(x => x.Dimensions.Unit.Description);
                        if (!shell.Code.Contains("FREIGHT"))
                        {
                            if (shell.Units > 0)
                            {
                                shell.DisplayUnits = "Units: " + shell.Units;
                                issuingHoldings.Add(shell);
                            }
                        }
                    }
                }
                RefreshLists();
                LoadProductImages();
            }
        }
        private CoreTable DoQuery(Filter filter)
        {
            try
            {
                return new Client().Query
                       (
                       filter,
                       new Columns
                       (
                           x => x.ID, //0
                           x => x.Product.Code, //1
                           x => x.Product.Name, //2
                           x => x.Style.Description, //3
                           x => x.Dimensions.UnitSize, //4
                           x => x.Units, //5
                           x => x.Location.ID, //6
                           x => x.Job.ID, //7
                           x => x.Job.Name, //8
                           x => x.Job.JobNumber, //9
                           x => x.Style.ID, //10
                           x => x.Style.Code, //11
                           x => x.Product.ID, //12
                           x => x.Product.Image.ID, //13
                           x => x.Dimensions.Unit.ID, //14
                           x => x.Dimensions.Quantity, //15
                           x => x.Dimensions.Length, //16
                           x => x.Dimensions.Width, //17
                           x => x.Dimensions.Height, //18
                           x => x.Dimensions.Weight, //19
                           x => x.Dimensions.Value, //20
                           x => x.Dimensions.Unit.HasHeight, //21
                           x => x.Dimensions.Unit.HasLength, //22
                           x => x.Dimensions.Unit.HasWidth, //23
                           x => x.Dimensions.Unit.HasWeight, //24
                           x => x.Dimensions.Unit.HasQuantity, //25
                           x => x.Dimensions.Unit.Formula, //26
                           x => x.Dimensions.Unit.Format, //27
                           x => x.Dimensions.Unit.Code, //28
                           x => x.Dimensions.Unit.Description //29
                           ),
                       null
                       );
            }
            catch (Exception ex)
            {
                InABox.Mobile.MobileLogging.Log(ex);
                return null;
            }
        }
        private void LoadProductImages()
        {
            Task.Run(() =>
            {
                List imageIDs = new List();
                foreach (var item in issuingHoldings)
                {
                    if (item.ImageID != Guid.Empty)
                        imageIDs.Add(item.ImageID);
                }
                CoreTable table = QueryDocuments(imageIDs);
                while (table == null)
                    table = QueryDocuments(imageIDs);
                foreach (CoreRow row in table.Rows)
                {
                    Guid id = row.Get(x => x.ID);
                    var item = issuingHoldings.FirstOrDefault(x => x.ImageID == id);
                    item.ImageSource = ImageSource.FromStream(() => new MemoryStream(row.Get(x => x.Data)));
                    item.ImageVisible = true;
                    if (DeviceType == "Tablet")
                    {
                        item.LastRowHeight = 300;
                    }
                    else
                    {
                        item.LastRowHeight = 150;
                    }
                }
                Device.BeginInvokeOnMainThread(() =>
                {
                    issuingListView.ItemsSource = null;
                    issuingListView.ItemsSource = issuingHoldings;
                });
            });
        }
        private CoreTable QueryDocuments(List imageIDs)
        {
            try
            {
                return new Client().Query(new Filter(x => x.ID).InList(imageIDs.ToArray()),
                        new Columns(x => x.ID, x => x.Data));
            }
            catch (Exception ex)
            {
                InABox.Mobile.MobileLogging.Log(ex);
                return null;
            }
        }
        private void LoadImages()
        {
            Task.Run(() =>
            {
                foreach (StockHoldingShell_Old shell in issuingHoldings)
                {
                    if (shell.ImageID != Guid.Empty)
                    {
                        CoreTable table = new Client().Query(new Filter(x => x.ID).IsEqualTo(shell.ImageID));
                        if (table.Rows.Any())
                        {
                            CoreRow docrow = table.Rows.FirstOrDefault();
                            if (docrow != null)
                            {
                                byte[] data = docrow.Get(x => x.Data);
                                ImageSource src = ImageSource.FromStream(() => new MemoryStream(data));
                                if (src != null)
                                {
                                    shell.ImageSource = src;
                                    shell.ImageVisible = true;
                                    if (DeviceType == "Tablet")
                                    {
                                        shell.LastRowHeight = 300;
                                    }
                                    else
                                    {
                                        shell.LastRowHeight = 150;
                                    }
                                    Device.BeginInvokeOnMainThread(() =>
                                    {
                                        issuingListView.ItemsSource = null;
                                        issuingListView.ItemsSource = issuingHoldings;
                                    });
                                }
                            }
                        }
                    }
                }
            });
        }
        private void CollapseExpanderOnButtonPress()
        {
            if (issuingExpander.State.Equals(ExpandState.Expanding) || issuingExpander.State.Equals(ExpandState.Expanded))
            {
                issuingExpander.IsExpanded = false;
                issuingFrame.HeightRequest = frameHeight;
                ForceLayout();
            }
            if (receivingExpander.State.Equals(ExpandState.Expanding) || receivingExpander.State.Equals(ExpandState.Expanded))
            {
                receivingExpander.IsExpanded = false;
                receivingFrame.HeightRequest = frameHeight;
                ForceLayout();
            }
        }
        //TODO
        private StockHoldingShell_Old DuplicateShell(StockHoldingShell_Old shell)
        {
            StockHoldingShell_Old NewShell = new StockHoldingShell_Old()
            {
                ID = shell.ID,
                Code = shell.Code,
                Name = shell.Name,
                Finish = shell.Finish,
                Units = shell.Units,
                DisplayUnits = shell.DisplayUnits,
                JobID = shell.JobID,
                JobName = shell.JobName,
                JobNumber = shell.JobNumber,
                DisplayJob = shell.DisplayJob,
                StyleName = shell.StyleName,
                StyleID = shell.StyleID,
                StyleCode = shell.StyleCode,
                ProductID = shell.ProductID,
                DisplaySize = shell.DisplaySize,
                LastRowHeight = shell.LastRowHeight,
                ImageID = shell.ImageID,
                ImageSource = shell.ImageSource,
                ImageVisible = shell.ImageVisible,
                DimensionsUnitID = shell.DimensionsUnitID,
                DimensionsQuantity = shell.DimensionsQuantity,
                DimensionsLength = shell.DimensionsLength,
                DimensionsWidth = shell.DimensionsWidth,
                DimensionsHeight = shell.DimensionsHeight,
                DimensionsWeight = shell.DimensionsWeight,
                DimensionsValue = shell.DimensionsValue,
                DimensionsUnitSize = shell.DimensionsUnitSize,
                DimensionsHasHeight = shell.DimensionsHasHeight,
                DimensionsHasLength = shell.DimensionsHasLength,
                DimensionsHasWidth = shell.DimensionsHasWidth,
                DimensionsHasWeight = shell.DimensionsHasWeight,
                DimensionsHasQuantity = shell.DimensionsHasQuantity,
                DimensionsUnitFormula = shell.DimensionsUnitFormula,
                DimensionsUnitFormat = shell.DimensionsUnitFormat,
                DimensionsUnitCode = shell.DimensionsUnitCode,
                DimensionsUnitDescription = shell.DimensionsUnitDescription,
            };
            return NewShell;
        }
        private void IssuingExpander_Tapped(object sender, EventArgs e)
        {
            if (issuingExpander.State.Equals(ExpandState.Expanding) || issuingExpander.State.Equals(ExpandState.Expanded))
            {
            }
            else if (issuingExpander.State.Equals(ExpandState.Collapsing) || issuingExpander.State.Equals(ExpandState.Collapsed))
            {
                issuingFrame.HeightRequest = frameHeight;
                ForceLayout();
            }
        }
        private void ReceivingExpander_Tapped(object sender, EventArgs e)
        {
            if (receivingExpander.State.Equals(ExpandState.Expanding) || receivingExpander.State.Equals(ExpandState.Expanded))
            {
            }
            else if (receivingExpander.State.Equals(ExpandState.Collapsing) || receivingExpander.State.Equals(ExpandState.Collapsed))
            {
                receivingFrame.HeightRequest = frameHeight;
                ForceLayout();
            }
        }
        private void ReceivingStockLocation_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                receivingLocationLbl.Text = ReceivingStockLocation.Description;
            });
        }
        private void IssuingStockLocation_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                issuingLocationLbl.Text = IssuingStockLocation.Description;
            });
        }
        private async void LoadDefaultStyle()
        {
            try
            {
                await Task.Run(() =>
                {
                    CoreTable table = new Client().Query(
                        new Filter(x => x.ID).IsEqualTo(ReceivingStockLocation.Job.ID),
                        new Columns(x => x.Style.ID, x => x.Style.Code, x => x.Style.Description)
                    );
                    if (table.Rows.Any())
                    {
                        List list = table.Rows.First().Values;
                        if (list[0] == null) { list[0] = Guid.Empty; } //0
                        if (list[1] == null) { list[1] = ""; } //1
                        if (list[2] == null) { list[2] = ""; } //2
                        DefaultStyle.ID = Guid.Parse(list[0].ToString());
                        DefaultStyle.Code = list[1].ToString();
                        DefaultStyle.Description = list[2].ToString();
                    }
                });
            }
            catch { }
        }
        private void LoadFavourites()
        {
            try
            {
                CoreTable table = new Client().Query
                   (
                   new Filter(x => x.Favourite).IsEqualTo(true),
                   new Columns(x => x.ID, x => x.Code, x => x.Description)
                   );
                if (table.Rows.Any())
                {
                    foreach (CoreRow row in table.Rows)
                    {
                        if (favourites.Count < 3)
                        {
                            List list = row.Values;
                            if (list[0] == null) list[0] = Guid.Empty;
                            if (list[1] == null) list[1] = "";
                            if (list[2] == null) list[2] = "";
                            StockLocation location = new StockLocation()
                            {
                                ID = Guid.Parse(list[0].ToString()),
                                Code = list[1].ToString(),
                                Description = list[2].ToString(),
                            };
                            favourites.Add(location);
                        }
                    }
                    Device.BeginInvokeOnMainThread(() =>
                    {
                        if (favourites.Count == 0)
                        {
                            DisableButtonOne();
                            DisableButtonTwo();
                            DisableButtonThree();
                        }
                        if (favourites.Count == 1)
                        {
                            issuingFavouriteBtn1.Text = favourites[0].Code;
                            receivingFavouriteBtn1.Text = favourites[0].Code;
                            DisableButtonTwo();
                            DisableButtonThree();
                        }
                        if (favourites.Count == 2)
                        {
                            issuingFavouriteBtn1.Text = favourites[0].Code;
                            receivingFavouriteBtn1.Text = favourites[0].Code;
                            issuingFavouriteBtn2.Text = favourites[1].Code;
                            receivingFavouriteBtn2.Text = favourites[1].Code;
                            DisableButtonThree();
                        }
                        if (favourites.Count == 3)
                        {
                            issuingFavouriteBtn1.Text = favourites[0].Code;
                            receivingFavouriteBtn1.Text = favourites[0].Code;
                            issuingFavouriteBtn2.Text = favourites[1].Code;
                            receivingFavouriteBtn2.Text = favourites[1].Code;
                            issuingFavouriteBtn3.Text = favourites[2].Code;
                            receivingFavouriteBtn3.Text = favourites[2].Code;
                        }
                    });
                }
            }
            catch
            {
            }
        }
        void DisableButtonOne()
        {
            issuingFavouriteBtn1.Text = "Not set";
            issuingFavouriteBtn1.IsEnabled = false;
            receivingFavouriteBtn1.Text = "Not set";
            receivingFavouriteBtn1.IsEnabled = false;
        }
        void DisableButtonTwo()
        {
            issuingFavouriteBtn2.Text = "Not set";
            issuingFavouriteBtn2.IsEnabled = false;
            receivingFavouriteBtn2.Text = "Not set";
            receivingFavouriteBtn2.IsEnabled = false;
        }
        void DisableButtonThree()
        {
            issuingFavouriteBtn3.Text = "Not set";
            issuingFavouriteBtn3.IsEnabled = false;
            receivingFavouriteBtn3.Text = "Not set";
            receivingFavouriteBtn3.IsEnabled = false;
        }
        #endregion
        #region Page Navigation / Saving
        private async void ExitWithoutSaving(object sender, EventArgs e)
        {
            if (receivingHoldings.Count > 0)
            {
                string chosenOption = await DisplayActionSheet("Leave without saving?", "Cancel", null, "Yes", "No");
                switch (chosenOption)
                {
                    case "Cancel":
                        return;
                    case "Yes":
                        Navigation.PopAsync();
                        break;
                    case "No":
                        return;
                    default:
                        return;
                }
            }
            else
                Navigation.PopAsync();
        }
        private void SaveBatch_Clicked(object sender, EventArgs e)
        {
            if (receivingHoldings.Count == 0)
                return;
            if (ReceivingStockLocation.ID == Guid.Empty && ReceivingJob.ID == Guid.Empty)
                return;
            RecTransCompletion completionPage = new RecTransCompletion(receivingHoldings, originalHoldings, IssuingStockLocation, ReceivingStockLocation, ReceivingJob);
            completionPage.OnRecTransCompleted += (() =>
            {
                ReceivingStockLocation = new StockLocation();
                ReceivingJob = new Job();
                receivingLocationLbl.Text = "Receiving Location:";
                receivingHoldings.Clear();
                originalHoldings.Clear();
                issuingListView.ItemsSource = null;
                receivingListView.ItemsSource = null;
                PreviousStyle = new ProductStyle();
                RefreshLists();
            });
            Navigation.PushAsync(completionPage);
        }
        #endregion
    }
    
}