using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Linq;
using MyAppApi;
using MyAppApi.BusinessLayer;
using MyAppApi.Models;
using MyAppApi.ViewModels;
using MyAppApi.Domain;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
 
namespace MyApp.Controllers
{
     /// <summary>
     /// Works like the Base class for ProductController class.
     /// ************************************* Do not make changes to this class *************************************
     /// ** Put your additional code in the ProductController class under the Controller folder. **
     /// *************************************************************************************************************
     /// </summary>
     public partial class ProductController : Controller
     {
         private Product _product;
         private ProductViewModel _productViewModel;
         private ProductForeachViewModel _productForEachViewModel;
 
         // constructor
         public ProductController(Product productProductViewModel productViewModelProductForeachViewModel productForeachViewModel)
         {
             _product = product;
             _productViewModel = productViewModel;
             _productForEachViewModel = productForeachViewModel;
         }
 
         #region actions used by their respective views
 
         /// <summary>
         /// GET: /Product/
         /// Gets the view used by the Index razor view
         /// </summary>
         public IActionResult Index()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/Add
         /// Gets the view model used by the Add razor view
         /// </summary>
         public async Task<IActionResultAdd(string urlReferrer = null)
         {
             // return the view model
             return await this.GetAddViewModelAsync(urlReferrer);
         }
 
         /// <summary>
         /// POST: /Product/Add
         /// Posts values from the Add razor view
         /// </summary>
         [HttpPost]
         [ValidateAntiForgeryToken]
         public async Task<IActionResultAdd(ProductViewModel viewModelstring returnUrl)
         {
             return await this.ValidateAndSave(CrudOperation.Add, viewModelreturnUrl);
         }
 
         /// <summary>
         /// GET: /Product/Update/*
         /// Gets the view model used by the Update razor view
         /// </summary>
         public async Task<IActionResultUpdate(int idstring urlReferrer = null)
         {
             // return view model
             return await this.GetUpdateViewModelAsync(idurlReferrer);
         }
 
         /// <summary>
         /// POST: /Product/Update/#
         /// Posts values from the Update razor view
         /// </summary>
         [HttpPost]
         [ValidateAntiForgeryToken]
         public async Task<IActionResultUpdate(int idProductViewModel viewModelstring returnUrl)
         {
             if (ModelState.IsValid)
                 return await this.ValidateAndSave(CrudOperation.Update, viewModelreturnUrlid);
 
             // if we got this far, something failed, redisplay form
             return await this.GetUpdateViewModelAsync(idreturnUrl);
         }
 
         /// <summary>
         /// GET: /Details/Details/#
         /// Gets the view model used by the Details razor view
         /// </summary>
         public async Task<IActionResultDetails(int idstring urlReferrer)
         {
             // fill the model by primary key
             await this.FillModelByPrimaryKeyAsync(id);
 
             // set and return the view model
             _productViewModel = await this.GetViewModelAsync("Details""Product"urlReferrer, _product, CrudOperation.None);
             return View(_productViewModel);
         }
 
         /// <summary>
         /// GET: /Product/ListCrudRedirect/
         /// Gets the view used by the ListCrudRedirect razor view
         /// </summary>
         public IActionResult ListCrudRedirect()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListReadOnly/
         /// Gets the view used by the ListReadOnly razor view
         /// </summary>
         public IActionResult ListReadOnly()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListCrud/
         /// Gets the view model used by the ListCrud razor view
         /// </summary>
         public async Task<IActionResultListCrud()
         {
             // return view model
             _productViewModel = await this.GetViewModelAsync("ListCrud");
             return View(_productViewModel);
         }
 
         /// <summary>
         /// POST: /Product/ListCrud
         /// Posts values from the ListCrud
         /// </summary>
         [HttpPost]
         public async Task<IActionResultListCrud(string inputSubmitstring serializedData)
         {
             // deserialize serializedData
             _product = JsonConvert.DeserializeObject<Product>(serializedData);
 
             // assign a value to the view model's Product (Model) property
             _productViewModel.Product = _product;
 
             if (ModelState.IsValid)
             {
                 CrudOperation operation = CrudOperation.Add;
 
                 if (inputSubmit == "Update")
                     operation = CrudOperation.Update;
 
                 try
                 {
                     // add a new record or update an existing record
                     await AddEditProductAsync(_productViewModel, operationtrue);
                 }
                 catch(Exception ex)
                 {
                     ModelState.AddModelError(""ex.Message);
                 }
             }
 
             return Json(true);
         }
 
         /// <summary>
         /// GET: /Product/ListTotals/
         /// Gets the view used by the ListTotals razor view
         /// </summary>
         public IActionResult ListTotals()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListSearch/
         /// Gets the view model used by the ListSearch razor view
         /// </summary>
         public async Task<IActionResultListSearch()
         {
             // return view model
             _productViewModel = await this.GetViewModelAsync("ListSearch");
             return View(_productViewModel);
         }
 
         /// <summary>
         /// GET: /Product/ListScrollLoad/
         /// Gets the view used by the ListScrollLoad razor view
         /// </summary>
         public IActionResult ListScrollLoad()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListInline/
         /// Gets the view model used by the ListInline razor view
         /// </summary>
         public async Task<IActionResultListInline()
         {
             // return view model
             _productViewModel = await this.GetViewModelAsync("ListInline");
             return View(_productViewModel);
         }
 
         /// <summary>
         /// POST: /Product/ListInlineAdd
         /// Posts the values from the ListInlineAdd
         /// </summary>
         [HttpPost]
         public async Task<IActionResultListInlineAdd([FromBody]string modelString)
         {
             return await this.ListInlineAddOrUpdate(modelStringCrudOperation.Add);
         }
 
         /// <summary>
         /// POST: /Product/ListInlineUpdate
         /// Posts the values from the ListInlineUpdate
         /// </summary>
         [HttpPost]
         public async Task<IActionResultListInlineUpdate([FromBody]string modelString)
         {
             return await this.ListInlineAddOrUpdate(modelStringCrudOperation.Update);
         }
 
         /// <summary>
         /// GET: /Product/ListForeach
         /// Gets the view model used by the ListForeach razor view
         /// </summary>
         public async Task<IActionResultListForeach(string sidxstring sordintpage)
         {
             // get the default number of rows to show
             int rows = Functions.GetGridNumberOfRows();
 
             // the numberOfPagesToShow is used to show the "< First..." link in the razor view
             int numberOfPagesToShow = Functions.GetGridNumberOfPagesToShow();
 
             // when page is null, set it to 1
             int currentPage = page is null ? 1 : Convert.ToInt32(page);
 
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCount/");
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(currentPagerowstotalRecords);
 
             // get records based on filters
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTake/?rows=" + rows + "&page=" + currentPage + "&sidx=" + sidx + "&sord=" + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // fields and titles
             string[,] fieldNames = new string[,] {
                 {"ProductID""Product ID"},
                 {"ProductName""Product Name"},
                 {"SupplierID""Supplier ID"},
                 {"CategoryID""Category ID"},
                 {"QuantityPerUnit""Quantity Per Unit"},
                 {"UnitPrice""Unit Price"},
                 {"UnitsInStock""Units In Stock"},
                 {"UnitsOnOrder""Units On Order"},
                 {"ReorderLevel""Reorder Level"},
                 {"Discontinued""Discontinued"}
             };
 
             // assign values to the view model
             _productForEachViewModel.ProductData = objProductsList;
             _productForEachViewModel.ProductFieldNames = fieldNames;
             _productForEachViewModel.TotalPages = totalPages;
             _productForEachViewModel.CurrentPage = currentPage;
             _productForEachViewModel.FieldToSort = String.IsNullOrEmpty(sidx) ? "ProductID" : sidx;
             _productForEachViewModel.FieldSortOrder = String.IsNullOrEmpty(sord) ? "asc" : sord;
             _productForEachViewModel.FieldToSortWithOrder = String.IsNullOrEmpty(sidx) ? "ProductID" : (sidx + " " + sord).Trim();
             _productForEachViewModel.NumberOfPagesToShow = numberOfPagesToShow;
             _productForEachViewModel.StartPage = Functions.GetPagerStartPage(currentPagenumberOfPagesToShow);
             _productForEachViewModel.EndPage = Functions.GetPagerEndPage(_productForEachViewModel.StartPage, numberOfPagesToShowtotalPages);
 
             // return the view model
             return View(_productForEachViewModel);
         }
 
         /// <summary>
         /// GET: /Product/ListMasterDetailGridBySupplierID/
         /// Gets the view used by the ListMasterDetailGridBySupplierID razor view
         /// </summary>
         public IActionResult ListMasterDetailGridBySupplierID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListMasterDetailGridByCategoryID/
         /// Gets the view used by the ListMasterDetailGridByCategoryID razor view
         /// </summary>
         public IActionResult ListMasterDetailGridByCategoryID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListMasterDetailSubGridBySupplierID/
         /// Gets the view used by the ListMasterDetailSubGridBySupplierID razor view
         /// </summary>
         public IActionResult ListMasterDetailSubGridBySupplierID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListMasterDetailSubGridByCategoryID/
         /// Gets the view used by the ListMasterDetailSubGridByCategoryID razor view
         /// </summary>
         public IActionResult ListMasterDetailSubGridByCategoryID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListMultipleDelete/
         /// Gets the view used by the ListMultipleDelete razor view
         /// </summary>
         public IActionResult ListMultipleDelete()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListGroupedBySupplierID/
         /// Gets the view used by the ListGroupedBySupplierID razor view
         /// </summary>
         public IActionResult ListGroupedBySupplierID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListGroupedByCategoryID/
         /// Gets the view used by the ListGroupedByCategoryID razor view
         /// </summary>
         public IActionResult ListGroupedByCategoryID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListTotalsGroupedBySupplierID/
         /// Gets the view used by the ListTotalsGroupedBySupplierID razor view
         /// </summary>
         public IActionResult ListTotalsGroupedBySupplierID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// GET: /Product/ListTotalsGroupedByCategoryID/
         /// Gets the view used by the ListTotalsGroupedByCategoryID razor view
         /// </summary>
         public IActionResult ListTotalsGroupedByCategoryID()
         {
             // return view
             return View();
         }
 
         /// <summary>
         /// Gets the view used by the ListBySupplierID razor view
         /// </summary>
         public async Task<IActionResultListBySupplierID()
         {
             // get records
             List<SupplierobjSuppliersList = null;
             string responseBody = await Functions.HttpClientGetAsync("SupplierApi/SelectSupplierDropDownListData/");
 
             // make sure responseBody is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody))
                 objSuppliersList = JsonConvert.DeserializeObject<List<Supplier>>(responseBody);
 
             // assign values to the view model
             _productViewModel.SupplierDropDownListData = objSuppliersList;
 
             // return the view model
             return View(_productViewModel);
         }
 
         /// <summary>
         /// Gets the view used by the ListByCategoryID razor view
         /// </summary>
         public async Task<IActionResultListByCategoryID()
         {
             // get records
             List<CategoryobjCategoriesList = null;
             string responseBody = await Functions.HttpClientGetAsync("CategoryApi/SelectCategoryDropDownListData/");
 
             // make sure responseBody is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody))
                 objCategoriesList = JsonConvert.DeserializeObject<List<Category>>(responseBody);
 
             // assign values to the view model
             _productViewModel.CategoryDropDownListData = objCategoriesList;
 
             // return the view model
             return View(_productViewModel);
         }
 
         /// <summary>
         /// GET: /Product/Unbound
         /// Gets the view model used by the Unbound razor view
         /// </summary>
         public async Task<IActionResultUnbound()
         {
             // set and return the view model
             _productViewModel = await this.GetViewModelAsync("Unbound""Product""/Home"nullCrudOperation.None, falsefalse);
             return View(_productViewModel);
         }
 
         /// <summary>
         /// POST: /Product/Unbound
         /// Post values fromy the Unbound razor view
         /// </summary>
         [HttpPost]
         [ValidateAntiForgeryToken]
         public async Task<IActionResultUnbound(ProductViewModel viewModelstring returnUrl)
         {
             if (ModelState.IsValid)
             {
                 // do something here before redirecting
 
                 if (Url.IsLocalUrl(returnUrl))
                     return Redirect(returnUrl);
                 else
                     return RedirectToAction("Index""Home");
             }
 
             // if we got this far, something failed, redisplay form
             _productViewModel = await this.GetViewModelAsync("Unbound""Product""/Home"nullCrudOperation.None, falsefalse);
             return View(_productViewModel);
         }
 
         #endregion
 
         #region public methods
 
         /// <summary>
         /// POST: /Product/Delete/#
         /// Deletes a record based on the id(s)
         /// </summary>
         [HttpPost]
         public async Task<IActionResultDelete(int id)
         {
             // delete data via web api
             HttpResponseMessage response = await Functions.HttpClientDeleteAsync("ProductApi/Delete/?id=" + id);
 
             // check the status of the httpclient delete operation
             if (response != null)
             {
                 if (response.IsSuccessStatusCode)
                     return Json(true);
                 else
                     return BadRequest(response.ReasonPhrase);
             }
 
             return BadRequest();
         }
 
         /// <summary>
         /// POST: /Product/DeleteMultiple/ids
         /// Deletes multiple records based on the comma-delimited ids
         /// </summary>
         [HttpPost]
         public async Task<IActionResultDeleteMultiple(string ids)
         {
             // delete multiple items via web api
             HttpResponseMessage response = await Functions.HttpClientDeleteAsync("ProductApi/DeleteMultiple?ids=" + ids);
 
             // check the status of the httpclient delete multiple operation
             if (response != null)
             {
                 if (response.IsSuccessStatusCode)
                     return Json(true);
                 else
                     return BadRequest(response.ReasonPhrase);
             }
 
             return BadRequest();
         }
 
         #endregion
 
         #region private methods
 
         /// <summary>
         /// Gets the view model used by the Add razor view
         /// </summary>
         private async Task<IActionResultGetAddViewModelAsync(string returnUrl = null)
         {
             // set the return url to /ListCrudRedirect when the returnUrl paramater is empty
             string url = String.IsNullOrEmpty(returnUrl) ? "/Product/ListCrudRedirect" : returnUrl;
 
             // set and return the view model
             _productViewModel = await this.GetViewModelAsync("Add""Product"urlnullCrudOperation.Add);
             return View(_productViewModel);
         }
 
         /// <summary>
         /// Gets the view model used by the Update razor view
         /// </summary>
         private async Task<IActionResultGetUpdateViewModelAsync(int idstring urlReferrer)
         {
             // fill the model by primary key
             await this.FillModelByPrimaryKeyAsync(id);
 
             // set and return the view model
             _productViewModel = await this.GetViewModelAsync("Update""Product"urlReferrer, _product, CrudOperation.Update);
             return View(_productViewModel);
         }
 
         /// <summary>
         /// Used when adding a new record or updating an existing record
         /// </summary>
         /// <param name="viewModel">ProductViewModel</param>
         /// <param name="operation">Operation to Add a new record or Update an existing record</param>
         /// <param name="isForListInlineOrListCrud">Used by the razor Views with ListInline or ListCrud when true</param>
         /// <returns>Task of IActionResult</returns>
         private async Task<IActionResultAddEditProductAsync(ProductViewModel viewModelCrudOperation operationbool isForListInlineOrListCrud = false)
         {
             Product model = viewModel.Product;
 
             // serialize the model to json
             string serializedModel = JsonConvert.SerializeObject(model);
 
             // web api url for Add
             string webApiUrl = "ProductApi/Insert?isForListInlineOrListCrud=" + isForListInlineOrListCrud;
 
             // web api url for Update
             if (operation == CrudOperation.Update)
                 webApiUrl = "ProductApi/Update?isForListInlineOrListCrud=" + isForListInlineOrListCrud;
 
             // post data via web api
             HttpResponseMessage response = await Functions.HttpClientPostAsync(webApiUrlserializedModel);
 
             // check the status of the httpclient post operation
             if (response != null)
             {
                 if (response.IsSuccessStatusCode)
                     return Ok();
                 else
                     return BadRequest(response.ReasonPhrase);
             }
 
             return BadRequest();
         }
 
         /// <summary>
         /// Gets the view model based on the actionName
         /// </summary>
         private async Task<ProductViewModelGetViewModelAsync(string actionName,
         string controllerName = "Product"string returnUrl = nullProduct objProduct = null,
         CrudOperation operation = CrudOperation.None, bool isFillSupplierDdl = truebool isFillCategoryDdl = true)
         {
             // assign values to the view model
             _productViewModel.Product = objProduct;
             _productViewModel.Operation = operation;
             _productViewModel.ViewControllerName = controllerName;
             _productViewModel.ViewActionName = actionName;
             _productViewModel.ViewReturnUrl = returnUrl;
 
             if(isFillSupplierDdl)
                 _productViewModel.SupplierDropDownListData = await this.GetSupplierDropDownListDataAsync();
             else
                 _productViewModel.SupplierDropDownListData = null;
 
             if(isFillCategoryDdl)
                 _productViewModel.CategoryDropDownListData = await this.GetCategoryDropDownListDataAsync();
             else
                 _productViewModel.CategoryDropDownListData = null;
 
             // return the view model
             return _productViewModel;
         }
 
         /// <summary>
         /// Validates the Add or Update operation and Saves the data when valid and no errors.
         /// </summary>
         /// <param name="operation">Add or Update only.  CrudOperation.None is not permitted</param>
         /// <param name="productViewModel">The View Model</param>
         /// <param name="returnUrl">Url to return to after the operation</param>
         /// <param name="id">Optional.  But required when operation = CrudOperation.Update</param>
         /// <returns>View Model as IActionResult</returns>
         private async Task<IActionResultValidateAndSave(CrudOperation operationProductViewModel productViewModelstring returnUrlintid = null)
         {
             if (operation == CrudOperation.None)
                 throw new ArgumentException("operation = CrudOperation.None is not valid for the ValidateAndSave method.");
 
             if (ModelState.IsValid)
             {
                 try
                 {
                     // add or update record
                     await this.AddEditProductAsync(productViewModeloperation);
 
                     if (Url.IsLocalUrl(returnUrl))
                         return Redirect(returnUrl);
                     else
                         return RedirectToAction("ListCrudRedirect""Product");
                 }
                 catch (Exception ex)
                 {
                     if (ex.InnerException != null)
                         ModelState.AddModelError(""ex.InnerException.Message);
                     else
                         ModelState.AddModelError(""ex.Message);
                 }
             }
 
             // if we got this far, something failed, redisplay form
             if (operation == CrudOperation.Add)
                 return await GetAddViewModelAsync(returnUrl);
             else
                 return await this.GetUpdateViewModelAsync(id.Value, returnUrl);
         }
 
         /// <summary>
         /// Fills the Product model information by primary key
         /// </summary>
         private async Task FillModelByPrimaryKeyAsync(int productID)
         {
             // select a record by primary key(s)
             string responseBody = await Functions.HttpClientGetAsync("ProductApi/SelectByPrimaryKey/?id=" + productID);
             Product objProduct = JsonConvert.DeserializeObject<Product>(responseBody);
 
             // assign values to the model
             _product.ProductID = objProduct.ProductID;
             _product.ProductName = objProduct.ProductName;
             _product.SupplierID = objProduct.SupplierID;
             _product.CategoryID = objProduct.CategoryID;
             _product.QuantityPerUnit = objProduct.QuantityPerUnit;
             _product.UnitPrice = objProduct.UnitPrice;
 
             if(objProduct.UnitsInStock.HasValue)
                 _product.UnitsInStockHidden = objProduct.UnitsInStock.ToString();
 
             if(objProduct.UnitsOnOrder.HasValue)
                 _product.UnitsOnOrderHidden = objProduct.UnitsOnOrder.ToString();
 
             if(objProduct.ReorderLevel.HasValue)
                 _product.ReorderLevelHidden = objProduct.ReorderLevel.ToString();
             _product.Discontinued = objProduct.Discontinued;
         }
 
         /// <summary>
         /// Selects records as a collection (List) of MyAppApi.Models.Supplier
         /// Retrieves a collection (List) of two colums per row, normally the Primary Key column and another column for use in a drop down list
         /// </summary>
         private async Task<List<MyAppApi.Models.Supplier>> GetSupplierDropDownListDataAsync()
         {
             // get records
             string responseBody = await Functions.HttpClientGetAsync("SupplierApi/SelectSupplierDropDownListData/");
             List<MyAppApi.Models.SupplierobjSuppliersList = JsonConvert.DeserializeObject<List<MyAppApi.Models.Supplier>>(responseBody);
 
             return objSuppliersList;
         }
 
         /// <summary>
         /// Selects records as a collection (List) of MyAppApi.Models.Category
         /// Retrieves a collection (List) of two colums per row, normally the Primary Key column and another column for use in a drop down list
         /// </summary>
         private async Task<List<MyAppApi.Models.Category>> GetCategoryDropDownListDataAsync()
         {
             // get records
             string responseBody = await Functions.HttpClientGetAsync("CategoryApi/SelectCategoryDropDownListData/");
             List<MyAppApi.Models.CategoryobjCategoriesList = JsonConvert.DeserializeObject<List<MyAppApi.Models.Category>>(responseBody);
 
             return objCategoriesList;
         }
 
         /// <summary>
         /// Deserializes the modelString and then Adds a New Record or Updates and existing record.
         /// This method is used by ListInlineAdd or ListInlineUpdate.
         /// </summary>
         private async Task<IActionResultListInlineAddOrUpdate(string modelStringCrudOperation operation)
         {
             // deserialize modelString
             _productViewModel.Product = JsonConvert.DeserializeObject<Product>("{" + modelString + "}");
 
             // add new record or update existing record
             await this.AddEditProductAsync(_productViewModel, operationtrue);
             return Json(true);
         }
 
         /// <summary>
         /// Gets json-formatted data based on the List of Products for use by the jqgrid.
         /// </summary>
         /// <param name="objProductsList">List of Products</param>
         /// <param name="totalPages">Total number of pages</param>
         /// <param name="page">Current page the grid is on</param>
         /// <param name="totalRecords">Total number of records</param>
         /// <returns>List of Products in Json format</returns>
         private JsonResult GetJsonData(List<ProductobjProductsListint totalPagesint pageint totalRecords)
         {
             // return a null in json for use by the jqgrid
             if (objProductsList is null)
                 return Json("{ total = 0, page = 0, records = 0, rows = null }");
 
             // create a serialized json object for use by the jqgrid
             var jsonData = new
             {
                 total = totalPages,
                 page,
                 records = totalRecords,
                 rows = (
                     from objProduct in objProductsList
                     select new
                     {
                         id = objProduct.ProductID,
                         cell = new string[] { 
                             objProduct.ProductID.ToString(),
                             objProduct.ProductName,
                             objProduct.SupplierID.HasValue ? objProduct.SupplierID.Value.ToString() : "",
                             objProduct.CategoryID.HasValue ? objProduct.CategoryID.Value.ToString() : "",
                             objProduct.QuantityPerUnit,
                             objProduct.UnitPrice.HasValue ? objProduct.UnitPrice.Value.ToString() : "",
                             objProduct.UnitsInStock.HasValue ? objProduct.UnitsInStock.Value.ToString() : "",
                             objProduct.UnitsOnOrder.HasValue ? objProduct.UnitsOnOrder.Value.ToString() : "",
                             objProduct.ReorderLevel.HasValue ? objProduct.ReorderLevel.Value.ToString() : "",
                             objProduct.Discontinued.ToString()
                         }
                     }).ToArray()
             };
 
             return Json(jsonData);
         }
 
         /// <summary>
         /// Gets json-formatted data based on the List of Products for use by the jqgrid.
         /// </summary>
         /// <param name="objProductsList">List of Products</param>
         /// <param name="totalPages">Total number of pages</param>
         /// <param name="page">Current page the grid is on</param>
         /// <param name="totalRecords">Total number of records</param>
         /// <returns>List of Products in Json format</returns>
         private JsonResult GetJsonDataGroupedBySupplierID(List<ProductobjProductsListint totalPagesint pageint totalRecords)
         {
             // return a null in json for use by the jqgrid
             if (objProductsList is null)
                 return Json("{ total = 0, page = 0, records = 0, rows = null }");
 
             // create a serialized json object for use by the jqgrid
             var jsonData = new
             {
                 total = totalPages,
                 page,
                 records = totalRecords,
                 rows = (
                     from objProduct in objProductsList
                     select new
                     {
                         id = objProduct.ProductID,
                         cell = new string[] { 
                             objProduct.ProductID.ToString(),
                             objProduct.ProductName,
                             objProduct.SupplierID.HasValue ? objProduct.SupplierID.Value.ToString() : "",
                             objProduct.CategoryID.HasValue ? objProduct.CategoryID.Value.ToString() : "",
                             objProduct.QuantityPerUnit,
                             objProduct.UnitPrice.HasValue ? objProduct.UnitPrice.Value.ToString() : "",
                             objProduct.UnitsInStock.HasValue ? objProduct.UnitsInStock.Value.ToString() : "",
                             objProduct.UnitsOnOrder.HasValue ? objProduct.UnitsOnOrder.Value.ToString() : "",
                             objProduct.ReorderLevel.HasValue ? objProduct.ReorderLevel.Value.ToString() : "",
                             objProduct.Discontinued.ToString(),
                             objProduct.SupplierID is null ? "" : objProduct.Supplier.CompanyName
 
                         }
                     }).ToArray()
             };
 
             return Json(jsonData);
         }
 
         /// <summary>
         /// Gets json-formatted data based on the List of Products for use by the jqgrid.
         /// </summary>
         /// <param name="objProductsList">List of Products</param>
         /// <param name="totalPages">Total number of pages</param>
         /// <param name="page">Current page the grid is on</param>
         /// <param name="totalRecords">Total number of records</param>
         /// <returns>List of Products in Json format</returns>
         private JsonResult GetJsonDataGroupedByCategoryID(List<ProductobjProductsListint totalPagesint pageint totalRecords)
         {
             // return a null in json for use by the jqgrid
             if (objProductsList is null)
                 return Json("{ total = 0, page = 0, records = 0, rows = null }");
 
             // create a serialized json object for use by the jqgrid
             var jsonData = new
             {
                 total = totalPages,
                 page,
                 records = totalRecords,
                 rows = (
                     from objProduct in objProductsList
                     select new
                     {
                         id = objProduct.ProductID,
                         cell = new string[] { 
                             objProduct.ProductID.ToString(),
                             objProduct.ProductName,
                             objProduct.SupplierID.HasValue ? objProduct.SupplierID.Value.ToString() : "",
                             objProduct.CategoryID.HasValue ? objProduct.CategoryID.Value.ToString() : "",
                             objProduct.QuantityPerUnit,
                             objProduct.UnitPrice.HasValue ? objProduct.UnitPrice.Value.ToString() : "",
                             objProduct.UnitsInStock.HasValue ? objProduct.UnitsInStock.Value.ToString() : "",
                             objProduct.UnitsOnOrder.HasValue ? objProduct.UnitsOnOrder.Value.ToString() : "",
                             objProduct.ReorderLevel.HasValue ? objProduct.ReorderLevel.Value.ToString() : "",
                             objProduct.Discontinued.ToString(),
                             objProduct.CategoryID is null ? "" : objProduct.Category.CategoryName
 
                         }
                     }).ToArray()
             };
 
             return Json(jsonData);
         }
 
         #endregion
 
         #region methods that return data in json format used by the jqgrid
 
         /// <summary>
         /// GET: /Product/GridData
         /// Gets the json needed by the jqgrid for use by the GridData
         /// </summary>
         public async Task<IActionResultGridData(string sidxstring sordint pageint rows)
         {
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCount/");
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTake/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonData(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataWithFilters
         /// Gets the json needed by the jqgrid for use by the GridDataWithFilters
         /// </summary>
         public async Task<IActionResultGridDataWithFilters(string _searchstring ndint rowsint pagestring sidxstring sordstring filters = "")
         {
             intproductID = null;
             string productName = String.Empty;
             intsupplierID = null;
             intcategoryID = null;
             string quantityPerUnit = String.Empty;
             decimalunitPrice = null;
             Int16unitsInStock = null;
             Int16unitsOnOrder = null;
             Int16reorderLevel = null;
             booldiscontinued = null;
 
             if (!String.IsNullOrEmpty(filters))
             {
                 // deserialize filters and get values being searched
                 var jsonResult = JsonConvert.DeserializeObject<Dictionary<stringdynamic>>(filters);
 
                 foreach (var rule in jsonResult["rules"])
                 {
                     if (rule["field"].Value.ToLower() == "productid")
                         productID = Convert.ToInt32(rule["data"].Value);
 
                     if (rule["field"].Value.ToLower() == "productname")
                         productName = rule["data"].Value;
 
                     if (rule["field"].Value.ToLower() == "supplierid")
                         supplierID = Convert.ToInt32(rule["data"].Value);
 
                     if (rule["field"].Value.ToLower() == "categoryid")
                         categoryID = Convert.ToInt32(rule["data"].Value);
 
                     if (rule["field"].Value.ToLower() == "quantityperunit")
                         quantityPerUnit = rule["data"].Value;
 
                     if (rule["field"].Value.ToLower() == "unitprice")
                         unitPrice = Convert.ToDecimal(rule["data"].Value);
 
                     if (rule["field"].Value.ToLower() == "unitsinstock")
                         unitsInStock = Convert.ToInt16(rule["data"].Value);
 
                     if (rule["field"].Value.ToLower() == "unitsonorder")
                         unitsOnOrder = Convert.ToInt16(rule["data"].Value);
 
                     if (rule["field"].Value.ToLower() == "reorderlevel")
                         reorderLevel = Convert.ToInt16(rule["data"].Value);
 
                     if (rule["field"].Value.ToLower() == "discontinued")
                         discontinued = Convert.ToBoolean(rule["data"].Value);
 
                 }
 
                 // sometimes jqgrid assigns a -1 to numeric fields when no value is assigned
                 // instead of assigning a null, we'll correct this here
                 if (productID == -1)
                     productID = null;
 
                 if (supplierID == -1)
                     supplierID = null;
 
                 if (categoryID == -1)
                     categoryID = null;
 
                 if (unitPrice == -1)
                     unitPrice = null;
 
                 if (unitsInStock == -1)
                     unitsInStock = null;
 
                 if (unitsOnOrder == -1)
                     unitsOnOrder = null;
 
                 if (reorderLevel == -1)
                     reorderLevel = null;
 
             }
 
             // get the total number of records based on filters
             int totalRecords = 0;
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCountDynamicWhere/?productID=" + productID + "&productName=" + productName + "&supplierID=" + supplierID + "&categoryID=" + categoryID + "&quantityPerUnit=" + quantityPerUnit + "&unitPrice=" + unitPrice + "&unitsInStock=" + unitsInStock + "&unitsOnOrder=" + unitsOnOrder + "&reorderLevel=" + reorderLevel + "&discontinued=" + discontinued);
             totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records based on filters
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTakeDynamicWhere/?productID=" + productID + "&productName=" + productName + "&supplierID=" + supplierID + "&categoryID=" + categoryID + "&quantityPerUnit=" + quantityPerUnit + "&unitPrice=" + unitPrice + "&unitsInStock=" + unitsInStock + "&unitsOnOrder=" + unitsOnOrder + "&reorderLevel=" + reorderLevel + "&discontinued=" + discontinued + "&rows=" + rows + "&startRowIndex=" + startRowIndex + "&sortByExpression=" + sidx + " " + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonData(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataWithTotals
         /// Gets the json needed by the jqgrid for use by the GridDataWithTotals
         /// </summary>
         public async Task<IActionResultGridDataWithTotals(string sidxstring sordint pageint rows)
         {
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCount/");
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTake/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonData(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataGroupedBySupplierID
         /// Gets the json needed by the jqgrid for use by the GridDataGroupedBySupplierID
         /// </summary>
         public async Task<IActionResultGridDataGroupedBySupplierID(string sidxstring sordint pageint rows)
         {
             // using a groupBy field in the jqgrid passes that field
             // along with the field to sort, remove the groupBy field
             string groupBy = "CompanyName asc, ";
             sidx = sidx.Replace(groupBy"");
 
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCount/");
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTake/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonDataGroupedBySupplierID(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataGroupedByCategoryID
         /// Gets the json needed by the jqgrid for use by the GridDataGroupedByCategoryID
         /// </summary>
         public async Task<IActionResultGridDataGroupedByCategoryID(string sidxstring sordint pageint rows)
         {
             // using a groupBy field in the jqgrid passes that field
             // along with the field to sort, remove the groupBy field
             string groupBy = "CategoryName asc, ";
             sidx = sidx.Replace(groupBy"");
 
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCount/");
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTake/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonDataGroupedByCategoryID(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataTotalsGroupedBySupplierID
         /// Gets the json needed by the jqgrid for use by the GridDataTotalsGroupedBySupplierID
         /// </summary>
         public async Task<IActionResultGridDataTotalsGroupedBySupplierID(string sidxstring sordint pageint rows)
         {
             // using a groupBy field in the jqgrid passes that field
             // along with the field to sort, remove the groupBy field
             string groupBy = "CompanyName asc, ";
             sidx = sidx.Replace(groupBy"");
 
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCount/");
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTake/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonDataGroupedBySupplierID(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataTotalsGroupedByCategoryID
         /// Gets the json needed by the jqgrid for use by the GridDataTotalsGroupedByCategoryID
         /// </summary>
         public async Task<IActionResultGridDataTotalsGroupedByCategoryID(string sidxstring sordint pageint rows)
         {
             // using a groupBy field in the jqgrid passes that field
             // along with the field to sort, remove the groupBy field
             string groupBy = "CategoryName asc, ";
             sidx = sidx.Replace(groupBy"");
 
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCount/");
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTake/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonDataGroupedByCategoryID(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataBySupplierID
         /// Gets the json needed by the jqgrid for use by the GridDataBySupplierID
         /// </summary>
         public async Task<IActionResultGridDataBySupplierID(string sidxstring sordint pageint rowsintsupplierID)
         {
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCountBySupplierID/?id=" + supplierID);
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTakeBySupplierID/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord + "&supplierID=" + supplierID);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonData(objProductsListtotalPagespagetotalRecords);
         }
 
         /// <summary>
         /// GET: /Product/GridDataByCategoryID
         /// Gets the json needed by the jqgrid for use by the GridDataByCategoryID
         /// </summary>
         public async Task<IActionResultGridDataByCategoryID(string sidxstring sordint pageint rowsintcategoryID)
         {
             // get the total number of records
             string responseBody1 = await Functions.HttpClientGetAsync("ProductApi/GetRecordCountByCategoryID/?id=" + categoryID);
             int totalRecords = JsonConvert.DeserializeObject<int>(responseBody1);
 
             // get the index where to start retrieving records from and the total number of pages
             (int startRowIndexint totalPages) = Functions.GetStartRowIndexAndTotalPages(pagerowstotalRecords);
 
             // get records
             List<ProductobjProductsList = null;
             string responseBody2 = await Functions.HttpClientGetAsync("ProductApi/SelectSkipAndTakeByCategoryID/?rows=" + rows + "&page=" + page + "&sidx=" + sidx + "&sord=" + sord + "&categoryID=" + categoryID);
 
             // make sure responseBody2 is not empty before deserialization
             if(!String.IsNullOrEmpty(responseBody2))
                 objProductsList = JsonConvert.DeserializeObject<List<Product>>(responseBody2);
 
             // return json data for use by the jqgrid
             return this.GetJsonData(objProductsListtotalPagespagetotalRecords);
         }
 
         #endregion
     }
}