/// <summary>
        /// Pushes all shopster products to shopify. Deals with all error states with an existing shopster Item. Deals with cases 1357, all ending in case7's state (see wiki).
        /// </summary>
        /// <param name="shopsterItems"></param>
        /// <param name="productMap"></param>
        /// <param name="shopifyMap"></param>
        /// <param name="shopifyIds"></param>
        /// <param name="shopifyItems"></param>
        /// <param name="storeAuth"></param>
        /// <param name="apiContext"></param>
        /// <returns>A count of how many products were fixed/changed.</returns>
        private int PushProductToShopify(IEnumerable<InventoryItemType> shopsterItems, ConnectsterProductMap productMap,
                                         ShopifyMetafieldMap shopifyMap, IList<int> shopifyIds,
                                         List<ShopifyProduct> shopifyItems, ShopifyStoreAuth storeAuth,
                                         ApiContext apiContext)
        {
            if (shopifyItems == null) throw new ArgumentNullException("shopifyItems");
            int returnCount = 0;
            //All of these are ending up in a Case7 (All good) state.
            foreach (InventoryItemType shopsterItem in shopsterItems)
            {
                InventoryItemType inventoryItem = shopsterItem;
                IList<ConnectsterProduct> mappings = productMap.GetMappedItems()
                    .Where(p => p.SourceId == Convert.ToInt32(inventoryItem.ItemId)).Select(p => p).ToList();
                if (mappings.Count > 0) //Cases 3,7
                {
                    foreach (ConnectsterProduct mapping in mappings)
                    {
                        if (!shopifyIds.Contains(mapping.DestinationId)) //If we have a broken mapping. (Case3)
                        {
                            //if the metafields have a mapping, fix the mapping
                            if (shopifyMap.GetDestinationIds().Contains(Convert.ToInt32(shopsterItem.ItemId)))
                            {
                                //There is a shopifyItem that wants to be linked to this shopsterItem
                                if (shopifyItems.Count > 0)
                                {
                                    ShopifyProduct shopifyItem = shopifyItems
                                        .Where(item => item.Id ==
                                                       shopifyMap.GetSourcesForDestiation(
                                                           Convert.ToInt32(shopsterItem.ItemId)).Take(1).First())
                                        .Select(item => item).First();
                                    if (shopifyItem.Id != null) mapping.DestinationId = (int) shopifyItem.Id;
                                    productMap.AddMapping(mapping); //Add mapping will update if it is already there.
                                    return returnCount;
                                }

                            }
                            else
                            {
                                //upload the product

                                List<InventoryCategoryType> categories =
                                    (shopsterItem.Categories == null || shopsterItem.Categories.Count < 1)
                                        ? new List<InventoryCategoryType>(1)
                                        : new List<InventoryCategoryType>(shopsterItem.Categories.Count);

                                if (shopsterItem.Categories != null)
                                    categories.AddRange(shopsterItem.Categories.Select(categoryId => _shopsterComm.GetCategory(apiContext, categoryId)));

                                ShopifyProduct sP = ShopsterifyConverter.convertItem(shopsterItem, categories);
                                ShopifyResponse<ShopifyProduct> response = _shopifyComm.CreateProduct(storeAuth, sP);
                                if (response.State == ResponseState.OK)
                                {
                                    _metaFieldShopsterProductId.Value = Convert.ToInt32(shopsterItem.ItemId).ToString();
                                    ShopifyResponse<ShopifyMetafield> responseMetafield =
                                        _shopifyComm.CreateMetafield(storeAuth, _metaFieldShopsterProductId,
                                                                    response.ResponseObject.Id);
                                    if (responseMetafield == null) throw new NotImplementedException();

                                    mapping.DestinationId = response.ResponseObject.Id != null
                                                                ? (int) response.ResponseObject.Id
                                                                : 0;
                                    productMap.AddMapping(mapping); //Add mapping will update if it is already there.
                                    returnCount++;
                                }
                            }
                        }
                        else //Case7 update and ensure metafield map is correct.
                        {
                            //Todo enable the below comparison of Sourcedate and DestinationDate
                            //if (mapping.SourceDate > mapping.DestinationDate)

                            if (mapping.DestinationDate < DateTime.UtcNow.AddMinutes(-5))
                            {
                                List<InventoryCategoryType> categories =
                                    (shopsterItem.Categories == null || shopsterItem.Categories.Count < 1)
                                        ? new List<InventoryCategoryType>(1)
                                        : new List<InventoryCategoryType>(shopsterItem.Categories.Count);
                                if (shopsterItem.Categories != null)
                                    categories.AddRange(shopsterItem.Categories.Select(categoryId => _shopsterComm.GetCategory(apiContext, categoryId)));

                                ShopifyProduct shopifyProduct = ShopsterifyConverter.convertItem(shopsterItem,
                                                                                                 categories);

                                shopifyProduct.Id = productMap.GetProductTable()[Convert.ToInt32(shopsterItem.ItemId)];
                                ShopifyVariant[] shopifyVars =
                                    shopifyItems.Where(item => item.Id == shopifyProduct.Id).Select(
                                        item => item.Variants).FirstOrDefault();

                                foreach (ShopifyVariant sV in shopifyProduct.Variants)
                                {
                                    sV.ProductId = shopifyProduct.Id;
                                    if (shopifyVars != null) sV.Id = shopifyVars[0].Id;
                                }

                                ShopifyResponse<ShopifyProduct> response = _shopifyComm.UpdateProduct(storeAuth,
                                                                                                     shopifyProduct);
                                if (response.State == ResponseState.OK)
                                {
                                    //Todo add debug logging that this item was updated correctly
                                    returnCount++;
                                    logger.InfoFormat(
                                        "ConnectsterController:: Updated shopify item({0}) successfully.",
                                        shopifyProduct.Id);

                                    _database.UpdateShopifyProductTimeStamp(response.ResponseObject, DateTime.UtcNow);
                                }
                            }
                            else
                            {
                                logger.InfoFormat("ConnectsterController:: Skipped update due to timestamps.");
                            }
                        }
                    }
                }
                else //Cases 1, 5 -- Product exists, no mappings found, maybe on shopify
                {
                    InventoryItemType inventoryItemType = shopsterItem;
                    IList<ShopifyMetafieldMapping> metaFieldMappings = shopifyMap.GetMappedItems()
                        .Where(map => map.DestinationId == Convert.ToInt32(inventoryItemType.ItemId))
                        .Select(map => map).ToList();

                    if (metaFieldMappings.Count > 0)
                        //There are products on shopify that think they belong to this shopsteritem
                    {
                        //Case 5
                        foreach (ShopifyMetafieldMapping metaFieldMapping in metaFieldMappings)
                        {
                            //rebuild the mapping, this call pushes through to the db.
                            ShopifyMetafieldMapping mapping = metaFieldMapping;
                            InventoryItemType item1 = shopsterItem;
                            productMap.AddMapping(new ConnectsterProduct(shopsterItem, shopifyItems
                                                                                           .Where(
                                                                                               item =>
                                                                                               (item.Id ==
                                                                                                mapping.
                                                                                                    SourceId) &&
                                                                                               (mapping.
                                                                                                    DestinationId ==
                                                                                                Convert.ToInt32(
                                                                                                    item1.ItemId)))
                                                                                           .Select(item => item).Take(1)
                                                                                           .ToList()[0]));
                            returnCount++;
                        }
                    }
                    else //There aren't any products on shopify that belong to this shopsterItem
                    {
                        //Case 1
                        //upload the product
                        List<InventoryCategoryType> categories =
                            (shopsterItem.Categories == null || shopsterItem.Categories.Count < 1)
                                ? new List<InventoryCategoryType>(1)
                                : new List<InventoryCategoryType>(shopsterItem.Categories.Count);

                        if (shopsterItem.Categories != null)
                            categories.AddRange(shopsterItem.Categories.Select(categoryId => _shopsterComm.GetCategory(apiContext, categoryId)));

                        ShopifyProduct sP = ShopsterifyConverter.convertItem(shopsterItem, categories);
                        ShopifyResponse<ShopifyProduct> response = _shopifyComm.CreateProduct(storeAuth, sP);
                        if (response.State == ResponseState.OK)
                        {
                            _metaFieldShopsterProductId.Value = Convert.ToInt32(shopsterItem.ItemId).ToString();
                            ShopifyResponse<ShopifyMetafield> responseMetafield = _shopifyComm.CreateMetafield(
                                storeAuth, _metaFieldShopsterProductId, response.ResponseObject.Id);
                            if (responseMetafield.State == ResponseState.OK)
                            {
                                //create the mapping

                                var mapping = new ConnectsterProduct(shopsterItem, response.ResponseObject);
                                productMap.AddMapping(mapping);
                            }

                            returnCount++;
                        }
                    }
                }
            }

            return returnCount;
        }
        private bool DeleteProductAndDeleteMap(ShopifyStoreAuth shopifyAuth, ConnectsterProductMap productMap,
                                               ConnectsterProduct item)
        {
            //Attempt to delete the shopsterItem from shopify
            if (!_shopifyComm.DeleteProduct(shopifyAuth, item.DestinationId))
            {
                //maybe a communication error, try next time around
                //todo: error, logs
                return false;
            }

            //Delete the Mapping
            return (productMap.DeleteMapping(item));
        }