/// <summary>
    /// Calculates the variant data such as selected options, their categories etc.
    /// </summary>
    private void CalculateVariantData()
    {
        // Current selected options(item2 in tuple) in selectors and theirs categories(item1 in tuple)
        mSelectedOptionsInCategories = new List <Tuple <int, int> >();

        // All possible options and theirs categories in dictionary with option ID as a key and category ID as value
        mOptionsInCategories = new Dictionary <int, int>();

        mRelatedSelectors = new List <ProductOptionSelector>();

        // Categories used in variants
        IEnumerable <int> usedCategoriesInVariants = new List <int>();

        // Do not evaluate variants when there are no selectors displayed
        if (OptionSelectors.Any() && (Variants.Count != 0))
        {
            usedCategoriesInVariants = Variants.First().ProductAttributes.CategoryIDs;
        }

        // Get product options and categories from selectors
        foreach (var selector in OptionSelectors)
        {
            // Get option category of this selector
            var category = selector.OptionCategory;

            // Ignore non-attribute categories and categories not included in Variants
            if ((category.CategoryType == OptionCategoryTypeEnum.Attribute) && usedCategoriesInVariants.Contains(category.CategoryID))
            {
                string option = selector.GetSelectedSKUOptions();

                // Get selected option id for this selector and add new Tuple<category, option> to selected option collection
                int selectedOptionId = ValidationHelper.GetInteger(option, 0);
                mSelectedOptionsInCategories.Add(new Tuple <int, int>(category.CategoryID, selectedOptionId));

                // Get all options for this category from selector to reduce SQL queries
                DataSet dsAllOptions = selector.ProductOptionsData;

                if (DataHelper.DataSourceIsEmpty(dsAllOptions))
                {
                    continue;
                }

                List <int> allOptionsId = (List <int>)DataHelper.GetIntegerValues(dsAllOptions.Tables[0], "SKUID");

                // Add option ids (plus category ids) to dictionary
                allOptionsId.ForEach(opt =>
                {
                    if (!mOptionsInCategories.ContainsKey(opt))
                    {
                        mOptionsInCategories.Add(opt, category.CategoryID);
                    }
                });

                mRelatedSelectors.Add(selector);
            }
        }
    }
    /// <summary>
    /// Validates shopping cart item selector input data.
    /// </summary>
    private bool IsValid()
    {
        // Validates all product options
        if (ShowProductOptions)
        {
            return(OptionSelectors.All(selector => selector.IsValid()));
        }

        return(true);
    }