private bool ValidateSelections(ProductPageViewModel model)
        {
            bool result = false;

            if ((model.LocalProduct.HasOptions()))
            {
                if ((model.LocalProduct.HasVariants()))
                {
                    Variant v = model.LocalProduct.Variants.FindBySelectionData(model.Selections, model.LocalProduct.Options);
                    if ((v != null))
                    {
                        result = true;
                    }
                    else
                    {
                        model.ValidationMessage = "<div class=\"flash-message-warning\">Please select a size</div>";
                    }
                }
                else
                {
                    result = true;
                }

                // Make sure no "labels" are selected
                if (model.Selections.HasLabelsSelected())
                {
                    result = false;
                    model.ValidationMessage = "<div class=\"flash-message-warning\">Please make all selections before adding to cart.</div>";
                }
            }
            else
            {
                result = true;
            }

            return result;
        }
        private void RenderOptionsJavascript(ProductPageViewModel model)
        {
            if (!model.LocalProduct.HasOptions()) return;

            StringBuilder sb = new StringBuilder();
            sb.Append("<script type=\"text/javascript\">");

            // Evaluate Selections
            sb.Append("function EvaluateSelections() {" + System.Environment.NewLine);
            sb.Append(" var loadingUrl = '" + Url.Content("~/images/system/ajax-loader.gif") + "';" + System.Environment.NewLine);
            sb.Append(" var loadingTag = '<img src=\"' + loadingUrl + '\" border=\"0\" alt=\"loading...\" />';" + System.Environment.NewLine);
            //sb.Append(" $('#sku').html(loadingTag);")
            //sb.Append(" $('#pricewrapper').html(loadingTag);")
            sb.Append(" $('.buttons').hide();" + System.Environment.NewLine);
            sb.Append(" $('#localmessage').html('<label>&nbsp;</label><span class=\"choice\">' + loadingTag + '</span>');" + System.Environment.NewLine);
            //sb.Append(" $('#imgMain').attr('src',loadingUrl);"+ System.Environment.NewLine)

            // Write each option to temp varible so we can get it's value as a string
            // This ensures the JSON will get correctly quoted by JQuery
            foreach (Option opt in model.LocalProduct.Options)
            {
                if (opt.OptionType == OptionTypes.CheckBoxes | opt.OptionType == OptionTypes.DropDownList | opt.OptionType == OptionTypes.RadioButtonList)
                {
                    sb.Append("var opt" + opt.Bvin.Replace("-", "") + "=");
                    if (opt.OptionType == OptionTypes.RadioButtonList)
                    {
                        sb.Append("$('.radio" + opt.Bvin.Replace("-", "") + ":checked').val();" + System.Environment.NewLine);

                    }
                    else if (opt.OptionType == OptionTypes.CheckBoxes)
                    {
                        sb.Append("$('.check" + opt.Bvin.Replace("-", "") + ":checked').val();" + System.Environment.NewLine);
                    }
                    else
                    {
                        sb.Append("$('#opt" + opt.Bvin.Replace("-", "") + "').val();" + System.Environment.NewLine);
                    }
                    sb.Append("opt" + opt.Bvin.Replace("-", "") + "+='';" + System.Environment.NewLine);
                    //sb.Append("alert(opt" + opt.Bvin.Replace("-", "") + ");" + System.Environment.NewLine);
                }
            }

            sb.Append("$.post('" + Url.Content("~/products/validate") + "'," + System.Environment.NewLine);
            sb.Append(" {\"productbvin\":\"" + model.LocalProduct.Bvin + "\"" + System.Environment.NewLine);
            foreach (Option opt in model.LocalProduct.Options)
            {
                if (opt.OptionType == OptionTypes.CheckBoxes | opt.OptionType == OptionTypes.DropDownList | opt.OptionType == OptionTypes.RadioButtonList)
                {
                    sb.Append(", \"opt" + opt.Bvin.Replace("-", "") + "\": opt" + opt.Bvin.Replace("-", ""));
                }
            }
            sb.Append("}, " + System.Environment.NewLine);
            sb.Append("  function(data) {" + System.Environment.NewLine);
            //sb.Append(" alert(data.Message);" + System.Environment.NewLine);

            sb.Append(" if (data.Message === null || data.Message.Length < 1) { $('#localmessage').html('');} else {");
            sb.Append("$('#localmessage').html('<label>&nbsp;</label><span class=\"choice\">' + data.Message + '</span>');");
            sb.Append("}" + System.Environment.NewLine);

            sb.Append(" $('#imgMain').attr('src',data.ImageUrl);" + System.Environment.NewLine);
            sb.Append(" $('#sku').html(data.Sku);" + System.Environment.NewLine);
            sb.Append(" $('.stockdisplay').html(data.StockMessage);" + System.Environment.NewLine);
            sb.Append(" $('#pricewrapper').html(data.Price);" + System.Environment.NewLine);
            //sb.Append(" alert(data.IsValid); "+ System.Environment.NewLine)
            sb.Append(" if (data.IsValid === false) { $('.buttons').hide();} else { $('.buttons').show();}" + System.Environment.NewLine);
            sb.Append("  }, 'json');" + System.Environment.NewLine);
            // end post function
            sb.Append("}" + System.Environment.NewLine);

            // end evaluate function

            // CUT: moved this to separate ProductPage.js b/c there's no reason this should be hard-coded
            //// Document Ready Function
            //sb.Append("$(document).ready(function() {" + System.Environment.NewLine);

            //sb.Append("$(\".isoption\").change(function() {" + System.Environment.NewLine);
            //sb.Append(" EvaluateSelections();" + System.Environment.NewLine);
            //sb.Append(" return true;" + System.Environment.NewLine);
            //sb.Append("});" + System.Environment.NewLine);

            //sb.Append(" EvaluateSelections(); " + System.Environment.NewLine);

            //sb.Append("});" + System.Environment.NewLine + System.Environment.NewLine);
            //// End of Document Ready

            sb.Append("</script>" + System.Environment.NewLine);
            model.JavaScripts += sb.ToString();
        }
        private void RenderPrices(ProductPageViewModel model)
        {
            string userId = MTApp.CurrentCustomerId;
            StringBuilder sb = new StringBuilder();

            sb.Append("<div class=\"prices\">");

            UserSpecificPrice productDisplay = MTApp.PriceProduct(model.LocalProduct, MTApp.CurrentCustomer, null);
            if (productDisplay.ListPriceGreaterThanCurrentPrice)
            {
                sb.Append("<label>" + SiteTerms.GetTerm(SiteTermIds.ListPrice) + "</label>");
                sb.Append("<span class=\"choice\"><strike>");
                sb.Append(model.LocalProduct.ListPrice.ToString("C"));
                sb.Append("</strike></span>");
            }

            sb.Append("<label>" + SiteTerms.GetTerm(SiteTermIds.SitePrice) + "</label>");
            sb.Append("<span class=\"choice\">");
            sb.Append(productDisplay.DisplayPrice());
            sb.Append("</span>");

            if ((productDisplay.BasePrice < productDisplay.ListPrice) && (productDisplay.OverrideText.Trim().Length < 1))
            {
                sb.Append("<label>" + SiteTerms.GetTerm(SiteTermIds.YouSave) + "</label>");
                sb.Append("<span class=\"choice\">");
                sb.Append(productDisplay.Savings.ToString("c") + " - " + productDisplay.SavingsPercent + System.Threading.Thread.CurrentThread.CurrentUICulture.NumberFormat.PercentSymbol);
                sb.Append("</span>");
            }

            sb.Append("<div class=\"clear\"></div></div>");
            model.PreRenderedPrices = sb.ToString();
        }
        private void ParseSelections(ProductPageViewModel model)
        {
            OptionSelectionList result = new OptionSelectionList();

            foreach (Option opt in model.LocalProduct.Options)
            {
                OptionSelection selected = opt.ParseFromForm(Request.Form);
                if (selected != null)
                {
                    result.Add(selected);
                }
            }

            model.Selections = result;
        }
        private void RenderAdditionalImages(ProductPageViewModel model)
        {
            if (model.LocalProduct.Images.Count < 1) return;

            StringBuilder sb = new StringBuilder();
            sb.Append("<div class=\"additionalimages\">");
            foreach (ProductImage img in model.LocalProduct.Images)
            {
                RenderSingleAdditionalImage(sb, img);
            }
            sb.Append("</div>");
            model.PreRenderedImages = sb.ToString();
        }
        private void LoadLineItemValues(ProductPageViewModel model)
        {
            if (model.LineItemId.Trim().Length > 0)
            {
                long lineItemId = 0;
                long.TryParse(model.LineItemId, out lineItemId);

                Order o = SessionManager.CurrentShoppingCart(MTApp.OrderServices, MTApp.CurrentStore);
                if (o != null)
                {
                    var li = o.Items.Where(y => y.Id == lineItemId).SingleOrDefault();
                    if (li != null)
                    {
                        model.Quantity = li.Quantity;
                        model.Selections = li.SelectionData;
                    }
                }
            }
        }
        private void LoadRelatedItems(ProductPageViewModel model)
        {
            int MaxItemsToShow = 3;
            bool IncludeAutoSuggestions = true;

            List<ProductRelationship> relatedItems
                = MTApp.CatalogServices.ProductRelationships.FindForProduct(model.LocalProduct.Bvin);
            if (relatedItems == null) return;

            int maxItems = MaxItemsToShow;

            // we have fewer available than max to show
            if (relatedItems.Count < MaxItemsToShow)
            {
                if (IncludeAutoSuggestions)
                {
                    // try to fill in auto suggestions
                    int toAuto = MaxItemsToShow - relatedItems.Count;
                    List<ProductRelationship> autos = MTApp.GetAutoSuggestedRelatedItems(model.LocalProduct.Bvin, toAuto);
                    if (autos != null)
                    {
                        foreach (ProductRelationship r in autos)
                        {
                            relatedItems.Add(r);
                        }
                    }
                }

                maxItems = relatedItems.Count;
            }

            if (relatedItems.Count < 1) return;

            for (int i = 0; i < maxItems; i++)
            {
                string relatedBvin = relatedItems[i].RelatedProductId;
                Product related = MTApp.CatalogServices.Products.Find(relatedBvin);
                if (related != null)
                {
                    SingleProductViewModel item = new SingleProductViewModel(related, MTApp);
                    if (i == 0) item.IsFirstItem = true;
                    if (i == (maxItems - 1)) item.IsLastItem = true;
                    model.RelatedItems.Add(item);
                }
            }
        }
        private ProductPageViewModel IndexSetup(string slug)
        {
            ViewBag.BodyClass = "store-product-page";
            ProductPageViewModel model = new ProductPageViewModel();
            model.LocalProduct = ParseProductFromSlug(slug);
            RenderOptionsJavascript(model);

            // Page Title
            if (model.LocalProduct.MetaTitle.Trim().Length > 0)
            {
                ViewBag.Title = model.LocalProduct.MetaTitle;
            }
            else
            {
                ViewBag.Title = model.LocalProduct.ProductName;
            }

            // Meta Keywords
            if (model.LocalProduct.MetaKeywords.Trim().Length > 0)
            {
                ViewBag.MetaKeywords = model.LocalProduct.MetaKeywords;
            }

            // Meta Description
            if (model.LocalProduct.MetaDescription.Trim().Length > 0)
            {
                ViewBag.MetaDescription = model.LocalProduct.MetaDescription;
            }

            ViewBag.RelatedItemsTitle = SiteTerms.GetTerm(SiteTermIds.RelatedItems);
            ViewBag.AddToCartButtonUrl = MTApp.ThemeManager().ButtonUrl("addtocart", Request.IsSecureConnection);
            ViewBag.SubmitButtonUrl = MTApp.ThemeManager().ButtonUrl("submit", Request.IsSecureConnection);
            ViewBag.SaveLaterButton = MTApp.ThemeManager().ButtonUrl("SaveForLater", Request.IsSecureConnection);

            CheckForBackOrder(model);

            model.MainImageUrl = MerchantTribe.Commerce.Storage.DiskStorage.ProductImageUrlMedium(MTApp, model.LocalProduct.Bvin, model.LocalProduct.ImageFileSmall, Request.IsSecureConnection);
            // use first add'l image as main image
            //model.MainImageUrl = MerchantTribe.Commerce.Storage.DiskStorage.ProductAdditionalImageUrlMedium(MTApp, model.LocalProduct.Bvin,
            //    model.LocalProduct.Images.First() == null ? string.Empty : model.LocalProduct.Images.First().Bvin,
            //    model.LocalProduct.Images.First().FileName,
            //    Request.IsSecureConnection);

            model.MainImageAltText = model.LocalProduct.ImageFileSmallAlternateText;
            model.PreRenderedTypeValues = model.LocalProduct.GetTypeProperties(this.MTApp);

            // Prices
            RenderPrices(model);

            LoadRelatedItems(model);
            RenderAdditionalImages(model);

            if (Request.QueryString["LineItemId"] != null)
            {
                model.OrderId = Request.QueryString["OrderBvin"];
                model.LineItemId = Request.QueryString["LineItemId"];
            }

            if (SessionManager.IsUserAuthenticated(MTApp))
            {
                model.IsAvailableForWishList = true;
            }

            StringBuilder sb = new StringBuilder();

            sb.Append("<script src=\"" + Url.Content("~/scripts/tabs.js") + "\" type=\"text/javascript\"></script>");
            sb.Append("<script src=\"" + Url.Content("~/scripts/ProductPage.js") + "\" type=\"text/javascript\"></script>");
            sb.Append(model.JavaScripts);

            if (ViewBag.UseFaceBook == true)
            {
                sb.Append("<!-- FaceBook OpenGraph Tags -->");
                sb.Append("<meta property=\"og:title\" content=\"" + ViewBag.Title + "\"/>");
                sb.Append("<meta property=\"og:type\" content=\"product\"/>");
                sb.Append("<meta property=\"og:url\" content=\"" + ViewBag.CurrentUrl + "\"/>");
                sb.Append("<meta property=\"og:image\" content=\"" + model.MainImageUrl + "\"/>");
                sb.Append("<meta property=\"og:site_name\" content=\"" + ViewBag.StoreName + "\" />");
                sb.Append("<meta property=\"fb:admins\" content=\"" + ViewBag.FaceBookAdmins + "\" />");
                sb.Append("<meta property=\"fb:app_id\" content=\"" + ViewBag.FaceBookAppId + "\" />");
            }
            ViewData["PassedAnalyticsTop"] = sb.ToString();

            // moving this to overall template b/c we use like button on every page
            //StringBuilder sbb = new StringBuilder();
            //sbb.Append("<div id=\"fb-root\"></div>");
            //sbb.Append("<script>    (function (d, s, id) {");
            //sbb.Append("var js, fjs = d.getElementsByTagName(s)[0];");
            //sbb.Append("if (d.getElementById(id)) { return; }");
            //sbb.Append("js = d.createElement(s); js.id = id;");
            //sbb.Append("js.src = \"//connect.facebook.net/en_US/all.js#xfbml=1\";");
            //sbb.Append("fjs.parentNode.insertBefore(js, fjs);");
            //sbb.Append("} (document, 'script', 'facebook-jssdk'));</script>");

            //ViewData["PassedAnalyticsBottom"] += sbb.ToString();
            return model;
        }
        private void DetermineQuantityToAdd(ProductPageViewModel model)
        {
            int quantity = 0;
            string formQuantity = Request.Form["qty"];
            if (int.TryParse(formQuantity, out quantity))
            {
                if (model.LocalProduct.MinimumQty > 0)
                {
                    if (quantity < model.LocalProduct.MinimumQty)
                    {
                        FlashWarning(SiteTerms.ReplaceTermVariable(SiteTerms.GetTerm(SiteTermIds.ProductPageMinimumQuantityError), "quantity", model.LocalProduct.MinimumQty.ToString()));
                        quantity = -1;
                    }
                }
            }
            else
            {
                if (model.LocalProduct.MinimumQty > 0)
                {
                    quantity = model.LocalProduct.MinimumQty;
                }
                else
                {
                    quantity = 1;
                }
            }

            model.Quantity = quantity;
        }
 private void CheckForBackOrder(ProductPageViewModel model)
 {
     InventoryCheckData data = MTApp.CatalogServices.InventoryCheck(model.LocalProduct, string.Empty);
     model.StockMessage = data.InventoryMessage;
     model.IsAvailableForSale = data.IsAvailableForSale;
 }
        private ProductPageViewModel IndexSetup(string slug)
        {
            ViewBag.BodyClass = "store-product-page";
            ProductPageViewModel model = new ProductPageViewModel();
            model.LocalProduct = ParseProductFromSlug(slug);
            RenderOptionsJavascript(model);

            // Page Title
            if (model.LocalProduct.MetaTitle.Trim().Length > 0)
            {
                ViewBag.Title = model.LocalProduct.MetaTitle;
            }
            else
            {
                ViewBag.Title = model.LocalProduct.ProductName;
            }

            // Meta Keywords
            if (model.LocalProduct.MetaKeywords.Trim().Length > 0)
            {
                ViewBag.MetaKeywords = model.LocalProduct.MetaKeywords;
            }

            // Meta Description
            if (model.LocalProduct.MetaDescription.Trim().Length > 0)
            {
                ViewBag.MetaDescription = model.LocalProduct.MetaDescription;
            }

            ViewBag.RelatedItemsTitle = SiteTerms.GetTerm(SiteTermIds.RelatedItems);
            ViewBag.AddToCartButtonUrl = MTApp.ThemeManager().ButtonUrl("addtocart", Request.IsSecureConnection);
            ViewBag.SubmitButtonUrl = MTApp.ThemeManager().ButtonUrl("submit", Request.IsSecureConnection);
            ViewBag.SaveLaterButton = MTApp.ThemeManager().ButtonUrl("SaveForLater", Request.IsSecureConnection);

            CheckForBackOrder(model);

            model.MainImageUrl = MerchantTribe.Commerce.Storage.DiskStorage.ProductImageUrlMedium(MTApp, model.LocalProduct.Bvin, model.LocalProduct.ImageFileSmall, Request.IsSecureConnection);
            model.MainImageAltText = model.LocalProduct.ImageFileSmallAlternateText;
            model.PreRenderedTypeValues = model.LocalProduct.GetTypeProperties(this.MTApp);

            // Prices
            RenderPrices(model);

            LoadRelatedItems(model);
            RenderAdditionalImages(model);

            if (Request.QueryString["LineItemId"] != null)
            {
                model.OrderId = Request.QueryString["OrderBvin"];
                model.LineItemId = Request.QueryString["LineItemId"];
            }

            if (SessionManager.IsUserAuthenticated(MTApp))
            {
                model.IsAvailableForWishList = true;
            }
            return model;
        }
        private ProductPageViewModel IndexSetup(string slug)
        {
            ViewBag.BodyClass = "store-product-page";
            ProductPageViewModel model = new ProductPageViewModel();
            model.LocalProduct = ParseProductFromSlug(slug);
            RenderOptionsJavascript(model);


            // Page Title
            ViewBag.Title = model.LocalProduct.MetaTitle.Trim();
            if (model.LocalProduct.MetaTitle.Trim().Length > 0)
            {                
                ViewBag.Title = model.LocalProduct.MetaTitle;
            }
            else
            {             
                ViewBag.Title = model.LocalProduct.ProductName;
            }

            // Meta Keywords
            ViewBag.MetaKeywords = model.LocalProduct.MetaKeywords.Trim();
            if (model.LocalProduct.MetaKeywords.Trim().Length > 0)
            {             
                ViewBag.MetaKeywords = model.LocalProduct.MetaKeywords;
            }

            // Meta Description
            ViewBag.MetaDescription = model.LocalProduct.MetaDescription.Trim();
            if (model.LocalProduct.MetaDescription.Trim().Length > 0)
            {             
                ViewBag.MetaDescription = model.LocalProduct.MetaDescription;
            }
            

            ViewBag.RelatedItemsTitle = SiteTerms.GetTerm(SiteTermIds.RelatedItems);
            ViewBag.AddToCartButtonUrl = MTApp.ThemeManager().ButtonUrl("addtocart", Request.IsSecureConnection);
            ViewBag.SubmitButtonUrl = MTApp.ThemeManager().ButtonUrl("submit", Request.IsSecureConnection);
            ViewBag.SaveLaterButton = MTApp.ThemeManager().ButtonUrl("SaveForLater", Request.IsSecureConnection);

            CheckForBackOrder(model);

            // Allow custom image names instead of the auto-generated ones
            string imageName = model.LocalProduct.ImageFileMedium;
            if (imageName.Trim().Length < 3)
            {
                imageName = model.LocalProduct.ImageFileSmall;
            }
            model.MainImageUrl = MerchantTribe.Commerce.Storage.DiskStorage.ProductImageUrlMedium(MTApp, model.LocalProduct.Bvin, imageName, Request.IsSecureConnection);
            model.MainImageAltText = model.LocalProduct.ImageFileMediumAlternateText;
            if (model.MainImageAltText.Trim().Length < 1) model.MainImageAltText = model.LocalProduct.ImageFileSmallAlternateText;
            model.PreRenderedTypeValues = model.LocalProduct.GetTypeProperties(this.MTApp);

            // Prices                        
            RenderPrices(model);

            LoadRelatedItems(model);
            RenderAdditionalImages(model);

            if (Request.QueryString["LineItemId"] != null)
            {
                model.OrderId = Request.QueryString["OrderBvin"];
                model.LineItemId = Request.QueryString["LineItemId"];
            }

            if (SessionManager.IsUserAuthenticated(MTApp))
            {
                model.IsAvailableForWishList = true;
            }


            StringBuilder sb = new StringBuilder();

            sb.Append("<script src=\"" + Url.Content("~/scripts/tabs.js") + "\" type=\"text/javascript\"></script>");
            sb.Append("<script src=\"" + Url.Content("~/scripts/ProductPage.js") + "\" type=\"text/javascript\"></script>");
            sb.Append(model.JavaScripts);

            if (ViewBag.UseFaceBook == true)
            {
                sb.Append("<!-- FaceBook OpenGraph Tags -->");
                sb.Append("<meta property=\"og:title\" content=\"" + ViewBag.Title + "\"/>");
                sb.Append("<meta property=\"og:type\" content=\"product\"/>");
                sb.Append("<meta property=\"og:url\" content=\"" + ViewBag.CurrentUrl + "\"/>");
                sb.Append("<meta property=\"og:image\" content=\"" + model.MainImageUrl + "\"/>");
                sb.Append("<meta property=\"og:site_name\" content=\"" + ViewBag.StoreName + "\" />");
                sb.Append("<meta property=\"fb:admins\" content=\"" + ViewBag.FaceBookAdmins + "\" />");
                sb.Append("<meta property=\"fb:app_id\" content=\"" + ViewBag.FaceBookAppId + "\" />");
            }
            ViewData["AnalyticsTop"] += sb.ToString();

            StringBuilder sbb = new StringBuilder();
            sbb.Append("<div id=\"fb-root\"></div>");
            sbb.Append("<script>    (function (d, s, id) {");
            sbb.Append("var js, fjs = d.getElementsByTagName(s)[0];");
            sbb.Append("if (d.getElementById(id)) { return; }");
            sbb.Append("js = d.createElement(s); js.id = id;");
            sbb.Append("js.src = \"//connect.facebook.net/en_US/all.js#xfbml=1\";");
            sbb.Append("fjs.parentNode.insertBefore(js, fjs);");
            sbb.Append("} (document, 'script', 'facebook-jssdk'));</script>");

            ViewData["AnalyticsBottom"] += sbb.ToString();

            // Bread Crumbs
            var breadRender = new code.TemplateEngine.TagHandlers.BreadCrumbs();
            model.BreadCrumbsFinal = breadRender.RenderProduct(MTApp, new List<BreadCrumbItem>(), model.LocalProduct);

            // Columns
            var columnRender = new code.TemplateEngine.TagHandlers.ContentColumn();
            model.PreColumn = columnRender.RenderColumnToString(model.LocalProduct.PreContentColumnId, MTApp, ViewBag);
            model.PostColumn = columnRender.RenderColumnToString(model.LocalProduct.PostContentColumnId, MTApp, ViewBag);

            model.SwatchHtml = MerchantTribe.Commerce.Utilities.ImageHelper.GenerateSwatchHtmlForProduct(model.LocalProduct, this.MTApp);
        

            MTApp.CurrentRequestContext.CurrentProduct = model.LocalProduct;
            return model;
        }