private List <SamplePackageResult> GetSamplePackages(Control row, out int count)
    {
        GridView grid = (GridView)row.FindControl("SamplePackages");

        PackagingRule rule = new PackagingRule();

        rule.BoxHeight = decimal.Parse(((TextBox)row.FindControl("HeightField")).Text);
        rule.BoxLength = decimal.Parse(((TextBox)row.FindControl("LengthField")).Text);
        rule.BoxWidth  = decimal.Parse(((TextBox)row.FindControl("WidthField")).Text);
        rule.Limits.AddRange(
            ((BVModules_Shipping_Package_Rules_PackageMatchEditor)row.FindControl("PackageMatchEditor")).GetMatches());
        rule.Name       = ((TextBox)row.FindControl("NameField")).Text.Trim();
        rule.TareWeight = decimal.Parse(((TextBox)row.FindControl("TareWeightField")).Text);
        Packager packager = new Packager(rule);

        count = 0;

        // Scan all placed orders
        List <SamplePackageResult> results = new List <SamplePackageResult>();
        int rowCount = 0;

        foreach (Order order in Order.FindByCriteria(new OrderSearchCriteria(), -1, grid.PageSize * 5, ref rowCount))
        {
            Order heavyOrder = Order.FindByBvin(order.Bvin);

            // "Unship" all of the items so that the samples look like they
            // were just placed. Skip any orders with deleted items.
            bool skipOrder = false;
            foreach (LineItem lineitem in heavyOrder.Items)
            {
                if (lineitem.AssociatedProduct == null || lineitem.AssociatedProduct.ShippingMode == ShippingMode.None)
                {
                    skipOrder = true;
                }
                else
                {
                    lineitem.QuantityShipped = 0;
                }
            }
            if (skipOrder)
            {
                break;
            }

            ExtendedShippingGroupList groups = new ExtendedShippingGroupList();
            foreach (ShippingGroup group in heavyOrder.GetShippingGroups())
            {
                groups.Add(new ExtendedShippingGroup(0, group, group.Items));
            }

            foreach (ExtendedShippingGroup group in groups)
            {
                ExtendedShippingGroupList splitGroups    = packager.Split(group);
                List <String>             remainingItems = new List <string>();
                SamplePackageResult       result;

                Boolean matchingPackage = false;

                foreach (ExtendedShippingGroup splitGroup in splitGroups)
                {
                    if (splitGroup.Name.Equals(rule.Name))
                    {
                        matchingPackage = true;
                        count          += 1;

                        result              = new SamplePackageResult();
                        result.OrderNumber  = order.OrderNumber;
                        result.OrderDisplay = string.Format("<a href=\"{0}\" target=\"order\">{1}</a>",
                                                            Page.ResolveUrl(
                                                                string.Format("~/BVAdmin/Orders/ViewOrder.aspx?id={0}",
                                                                              order.Bvin)),
                                                            order.OrderNumber);
                        List <string> matchValues = new List <string>();
                        List <string> limitValues = new List <string>();
                        for (int index = 0; index < rule.Limits.Count; index++)
                        {
                            PackageMatch match      = rule.Limits[index];
                            string       matchValue =
                                PackagePropertiesHelper.GetPackagePropertyValue(splitGroup, match.PackageProperty, match.ItemProperty,
                                                                                match.CustomProperty, "1").ToString();
                            if (string.IsNullOrEmpty(matchValue))
                            {
                                matchValue = "(empty)";
                            }
                            matchValues.Add(matchValue);
                            string limitValue =
                                PackagePropertiesHelper.GetPackagePropertyValue(splitGroup, match.LimitPackageProperty, match.LimitItemProperty,
                                                                                match.LimitCustomProperty, match.Limit).ToString();
                            if (string.IsNullOrEmpty(limitValue))
                            {
                                limitValue = "(empty)";
                            }
                            limitValues.Add(limitValue);
                        }
                        result.MatchValues = string.Join(", ", matchValues.ToArray());
                        result.LimitValues = string.Join(", ", limitValues.ToArray());
                        result.Volume      = splitGroup.GetShippingVolume().ToString("0.000");
                        result.Weight      = splitGroup.GetShippingWeight().ToString("0.000");
                        if (splitGroup.HasBoxDimensions)
                        {
                            decimal boxVolume = splitGroup.BoxHeight * splitGroup.BoxLength * splitGroup.BoxWidth;
                            result.FillFactor = string.Format("{0:0.000}%", splitGroup.GetShippingVolume() * 100M / boxVolume);
                        }
                        else
                        {
                            result.FillFactor = "n/a";
                        }
                        List <string> lineitems = new List <string>();
                        foreach (LineItem lineitem in splitGroup.Items)
                        {
                            lineitems.Add(string.Format("{0:0} &times; {1}", lineitem.Quantity, lineitem.ProductSku));
                        }
                        result.Items = string.Join(", ", lineitems.ToArray());
                        results.Add(result);
                    }
                    else
                    {
                        foreach (LineItem lineitem in splitGroup.Items)
                        {
                            remainingItems.Add(string.Format("{0:0} &times; {1}", lineitem.Quantity, lineitem.ProductSku));
                        }
                    }

                    if (count > grid.PageSize * 5)
                    {
                        break;
                    }
                }

                // If there was at least one matching package, then list the unmatched items
                if (matchingPackage && (remainingItems.Count > 0))
                {
                    result              = new SamplePackageResult();
                    result.OrderNumber  = order.OrderNumber;
                    result.OrderDisplay = string.Format("<a href=\"{0}\" target=\"order\">{1}</a>",
                                                        Page.ResolveUrl(
                                                            string.Format("~/BVAdmin/Orders/ViewOrder.aspx?id={0}",
                                                                          order.Bvin)),
                                                        order.OrderNumber);
                    result.MatchValues = "unpackaged items";
                    result.Items       = string.Join(", ", remainingItems.ToArray());
                    results.Add(result);
                }
            }
            if (count > grid.PageSize * 5)
            {
                break;
            }
        }
        results.Sort();
        return(results);
    }
    private List<SamplePackageResult> GetSamplePackages(Control row, out int count)
    {
        GridView grid = (GridView) row.FindControl("SamplePackages");

        PackagingRule rule = new PackagingRule();
        rule.BoxHeight = decimal.Parse(((TextBox)row.FindControl("HeightField")).Text);
        rule.BoxLength = decimal.Parse(((TextBox)row.FindControl("LengthField")).Text);
        rule.BoxWidth = decimal.Parse(((TextBox)row.FindControl("WidthField")).Text);
        rule.Limits.AddRange(
            ((BVModules_Shipping_Package_Rules_PackageMatchEditor) row.FindControl("PackageMatchEditor")).GetMatches());
        rule.Name = ((TextBox)row.FindControl("NameField")).Text.Trim();
        rule.TareWeight = decimal.Parse(((TextBox)row.FindControl("TareWeightField")).Text);
        Packager packager = new Packager(rule);

        count = 0;

        // Scan all placed orders
        List<SamplePackageResult> results = new List<SamplePackageResult>();
        int rowCount = 0;
        foreach (Order order in Order.FindByCriteria(new OrderSearchCriteria(), -1, grid.PageSize * 5, ref rowCount))
        {
            Order heavyOrder = Order.FindByBvin(order.Bvin);

            // "Unship" all of the items so that the samples look like they
            // were just placed. Skip any orders with deleted items.
            bool skipOrder = false;
            foreach (LineItem lineitem in heavyOrder.Items)
            {
                if (lineitem.AssociatedProduct == null || lineitem.AssociatedProduct.ShippingMode == ShippingMode.None)
                    skipOrder = true;
                else
                    lineitem.QuantityShipped = 0;
            }
            if (skipOrder) break;

            ExtendedShippingGroupList groups = new ExtendedShippingGroupList();
            foreach (ShippingGroup group in heavyOrder.GetShippingGroups())
            {
                groups.Add(new ExtendedShippingGroup(0, group, group.Items));
            }

            foreach (ExtendedShippingGroup group in groups)
            {
                ExtendedShippingGroupList splitGroups = packager.Split(group);
                List<String> remainingItems = new List<string>();
                SamplePackageResult result;

                Boolean matchingPackage = false;

                foreach (ExtendedShippingGroup splitGroup in splitGroups)
                {
                    if (splitGroup.Name.Equals(rule.Name))
                    {
                        matchingPackage = true;
                        count += 1;

                        result = new SamplePackageResult();
                        result.OrderNumber = order.OrderNumber;
                        result.OrderDisplay = string.Format("<a href=\"{0}\" target=\"order\">{1}</a>",
                                                            Page.ResolveUrl(
                                                                string.Format("~/BVAdmin/Orders/ViewOrder.aspx?id={0}",
                                                                              order.Bvin)),
                                                            order.OrderNumber);
                        List<string> matchValues = new List<string>();
                        List<string> limitValues = new List<string>();
                        for (int index = 0; index < rule.Limits.Count; index++)
                        {
                            PackageMatch match = rule.Limits[index];
                            string matchValue =
                                PackagePropertiesHelper.GetPackagePropertyValue(splitGroup, match.PackageProperty, match.ItemProperty,
                                                             match.CustomProperty, "1").ToString();
                            if (string.IsNullOrEmpty(matchValue)) matchValue = "(empty)";
                            matchValues.Add(matchValue);
                            string limitValue =
                                PackagePropertiesHelper.GetPackagePropertyValue(splitGroup, match.LimitPackageProperty, match.LimitItemProperty,
                                    match.LimitCustomProperty, match.Limit).ToString();
                            if (string.IsNullOrEmpty(limitValue)) limitValue = "(empty)";
                            limitValues.Add(limitValue);
                        }
                        result.MatchValues = string.Join(", ", matchValues.ToArray());
                        result.LimitValues = string.Join(", ", limitValues.ToArray());
                        result.Volume = splitGroup.GetShippingVolume().ToString("0.000");
                        result.Weight = splitGroup.GetShippingWeight().ToString("0.000");
                        if (splitGroup.HasBoxDimensions)
                        {
                            decimal boxVolume = splitGroup.BoxHeight * splitGroup.BoxLength * splitGroup.BoxWidth;
                            result.FillFactor = string.Format("{0:0.000}%", splitGroup.GetShippingVolume() * 100M / boxVolume);
                        }
                        else
                        {
                            result.FillFactor = "n/a";
                        }
                        List<string> lineitems = new List<string>();
                        foreach (LineItem lineitem in splitGroup.Items)
                        {
                            lineitems.Add(string.Format("{0:0} &times; {1}", lineitem.Quantity, lineitem.ProductSku));
                        }
                        result.Items = string.Join(", ", lineitems.ToArray());
                        results.Add(result);
                    }
                    else
                    {
                        foreach (LineItem lineitem in splitGroup.Items)
                        {
                            remainingItems.Add(string.Format("{0:0} &times; {1}", lineitem.Quantity, lineitem.ProductSku));
                        }
                    }

                    if (count > grid.PageSize * 5) break;
                }

                // If there was at least one matching package, then list the unmatched items
                if (matchingPackage && (remainingItems.Count > 0))
                {
                    result = new SamplePackageResult();
                    result.OrderNumber = order.OrderNumber;
                    result.OrderDisplay = string.Format("<a href=\"{0}\" target=\"order\">{1}</a>",
                                                        Page.ResolveUrl(
                                                            string.Format("~/BVAdmin/Orders/ViewOrder.aspx?id={0}",
                                                                          order.Bvin)),
                                                        order.OrderNumber);
                    result.MatchValues = "unpackaged items";
                    result.Items = string.Join(", ", remainingItems.ToArray());
                    results.Add(result);
                }
            }
            if (count > grid.PageSize*5) break;
        }
        results.Sort();
        return results;
    }
    protected void PackagingRules_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName == "MoveDown")
        {
            String        id            = e.CommandArgument.ToString();
            Int32         index         = Settings.PackagingRules.IndexOf(id);
            PackagingRule packagingRule = Settings.PackagingRules[index];
            Settings.PackagingRules.RemoveAt(index);
            Settings.PackagingRules.Insert(index + 1, packagingRule);
            Settings.PackagingRules.Save();
            PackagingRules.DataBind();
        }
        else if (e.CommandName == "MoveUp")
        {
            String        id            = e.CommandArgument.ToString();
            Int32         index         = Settings.PackagingRules.IndexOf(id);
            PackagingRule packagingRule = Settings.PackagingRules[index];
            Settings.PackagingRules.RemoveAt(index);
            Settings.PackagingRules.Insert(index - 1, packagingRule);
            Settings.PackagingRules.Save();
            PackagingRules.DataBind();
        }
        else if (e.CommandName == "New")
        {
            // Create the default packaging rule
            PackagingRule packagingRule = new PackagingRule();
            packagingRule.Limits.Add(new PackageMatch());

            // Add or insert the settings into the list
            String id    = e.CommandArgument.ToString();
            Int32  index = Settings.PackagingRules.IndexOf(id);
            Settings.PackagingRules.Insert(index + 1, packagingRule);
            Settings.PackagingRules.Save();
            PackagingRules.DataBind();
            PackagingRules.EditIndex = index + 1;

            Page.Items["PackagingRules"] = packagingRule;
        }
        else if (e.CommandName == "Update")
        {
            if (Page.IsValid)
            {
                GridViewRow row = PackagingRules.Rows[PackagingRules.EditIndex];
                if (Page.IsValid)
                {
                    if (row != null)
                    {
                        PackageMatchList matches = ((BVModules_Shipping_Package_Rules_PackageMatchEditor)row.FindControl("PackageMatchEditor")).GetMatches();
                        foreach (PackageMatch match in matches)
                        {
                            if (match.PackageProperty == PackageProperties.Distance)
                            {
                                if (PostalCode.IsPostalDataInstalled())
                                {
                                    Anthem.Manager.AddScriptForClientSideEval("alert('No postal code data has been installed. The Distance property will always return -1.');");
                                    break;
                                }
                            }
                        }
                        Page.Items["Limits"] = matches;
                    }
                }
            }
        }
        else if (e.CommandName == "View")
        {
            if (Page.IsValid)
            {
                GridViewRow row = PackagingRules.Rows[PackagingRules.EditIndex];
                if (row != null)
                {
                    GridView grid = row.FindControl("SamplePackages") as GridView;
                    if (grid != null)
                    {
                        Int32 count;
                        grid.Visible = true;
                        Session["SamplePackagesData"] = GetSamplePackages(row, out count);
                        grid.DataSource = Session["SamplePackagesData"];
                        grid.DataBind();
                        if (count > grid.PageSize * 5)
                        {
                            grid.Caption = string.Format("This rule would create {0}+ packages", grid.PageSize * 5);
                        }
                        else
                        {
                            grid.Caption = string.Format("This rule would create {0} package", count);
                            if (count == 0 || count > 1)
                            {
                                grid.Caption += "s";
                            }
                        }
                        grid.Caption += " from your existing orders";
                    }
                }
            }
        }
    }
    protected void PackagingRules_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName == "MoveDown")
        {
            String id = e.CommandArgument.ToString();
            Int32 index = Settings.PackagingRules.IndexOf(id);
            PackagingRule packagingRule = Settings.PackagingRules[index];
            Settings.PackagingRules.RemoveAt(index);
            Settings.PackagingRules.Insert(index + 1, packagingRule);
            Settings.PackagingRules.Save();
            PackagingRules.DataBind();
        }
        else if (e.CommandName == "MoveUp")
        {
            String id = e.CommandArgument.ToString();
            Int32 index = Settings.PackagingRules.IndexOf(id);
            PackagingRule packagingRule = Settings.PackagingRules[index];
            Settings.PackagingRules.RemoveAt(index);
            Settings.PackagingRules.Insert(index - 1, packagingRule);
            Settings.PackagingRules.Save();
            PackagingRules.DataBind();
        }
        else if (e.CommandName == "New")
        {
            // Create the default packaging rule
            PackagingRule packagingRule = new PackagingRule();
            packagingRule.Limits.Add(new PackageMatch());

            // Add or insert the settings into the list
            String id = e.CommandArgument.ToString();
            Int32 index = Settings.PackagingRules.IndexOf(id);
            Settings.PackagingRules.Insert(index + 1, packagingRule);
            Settings.PackagingRules.Save();
            PackagingRules.DataBind();
            PackagingRules.EditIndex = index + 1;

            Page.Items["PackagingRules"] = packagingRule;
        }
        else if (e.CommandName == "Update")
        {
            if (Page.IsValid)
            {
                GridViewRow row = PackagingRules.Rows[PackagingRules.EditIndex];
                if (Page.IsValid)
                {
                    if (row != null)
                    {
                        PackageMatchList matches = ((BVModules_Shipping_Package_Rules_PackageMatchEditor) row.FindControl("PackageMatchEditor")).GetMatches();
                        foreach (PackageMatch match in matches)
                        {
                            if (match.PackageProperty == PackageProperties.Distance)
                            {
                                if (PostalCode.IsPostalDataInstalled())
                                {
                                    Anthem.Manager.AddScriptForClientSideEval("alert('No postal code data has been installed. The Distance property will always return -1.');");
                                    break;
                                }
                            }
                        }
                        Page.Items["Limits"] = matches;
                    }
                }
            }
        }
        else if (e.CommandName == "View")
        {
            if (Page.IsValid)
            {
                GridViewRow row = PackagingRules.Rows[PackagingRules.EditIndex];
                if (row != null)
                {
                    GridView grid = row.FindControl("SamplePackages") as GridView;
                    if (grid != null)
                    {
                        Int32 count;
                        grid.Visible = true;
                        Session["SamplePackagesData"] = GetSamplePackages(row, out count);
                        grid.DataSource = Session["SamplePackagesData"];
                        grid.DataBind();
                        if (count > grid.PageSize*5)
                        {
                            grid.Caption = string.Format("This rule would create {0}+ packages", grid.PageSize*5);
                        }
                        else
                        {
                            grid.Caption = string.Format("This rule would create {0} package", count);
                            if (count == 0 || count > 1) grid.Caption += "s";
                        }
                        grid.Caption += " from your existing orders";
                    }
                }
            }
        }
    }