// "Product List" pane
.tab-pane#tab-product-list(role="tabpanel")
  .card(ng-hide=" !productShowList()")
    .row
      .col-md-12
        h2 Product List
        .form-group
          label(for='product-filter') Filter
          input#product-filter.form-control(ng-model="productFilter" ng-change="productFilterChanged()" type='text', placeholder="Type part of the product name  (e.g. 'cha' for chardonnay)")
        //- form-group
        br
        p(ng-repeat="product in products")
          a.mouse-pointer(ng-click="productSelect(product.productId)")
            | {{product.name}}
          br
      //- col-md-12
    //- row
  //- card

  .card(ng-hide="productShowList()")
    .row
      .col-md-12
        h2 {{product.name}}
        small
          | {{product.supplier.company_name}}
          br
          br
        ul.nav.nav-tabs
          li.active
            a(href="#tab-product-details" data-toggle="tab") Details
          li
            a(href="#tab-product-descriptions" data-toggle="tab") Description
          li
            a(href="#tab-product-metadata" data-toggle="tab") SEO
          li
            a(href="#tab-product-variants" data-toggle="tab") Variants
        br
        .actions-wrap.hide.NOTYET
          a.btn(ng-click="product_backButton()") Back to product list
          a.btn(ng-click="productVariant_backButton()" ng-hide="productVariant_showList()") Back to variant list
          a.btn.btn-success(ng-click="productSaveButton()") Save
        //- actions-wrap

        .tab-content.clearfix
          // Product details pane
          #tab-product-details.tab-pane.active
            .form-group
              label(for='product-id') Id
              input#product-id.form-control(ng-model="product.productId" type='text', placeholder='Product Id', readonly='readonly')
              br

              label(for='product-name') Name
              input#product-name.form-control(ng-model="product.name" type='text', placeholder='Name')
              br

              label(for='product-categories') Categories
              input#product-categories.form-control(ng-model="product.categories" type='text', placeholder='categories')
              br

              label(for='product-popularity') Popularity
              input#product-popularity.form-control(ng-model="product.popularity" type='text', placeholder='')
              br

              label(for='product-teaIdAtSource') TEA Id at source
              input#product-teaIdAtSource.form-control(ng-model="product.teaIdAtSource" type='text', placeholder='teaIdAtSource')
              br

          // Metadata pane
          #tab-product-descriptions.tab-pane
            h2 Descriptions
            .form-group
              label(for='product-shortDescription') Short Description
              input#product-shortDescription.form-control(ng-model="product.shortDescription" type='text', placeholder='')
              br

              label(for='product-longDescription') Long Description
              //input#product-longDescription.form-control(ng-model="product.longDescription" type='text', placeholder='')
              // See https://github.com/lemonde/angular-ckeditor
              div(ckeditor="ckeditorOptions", ng-model="product.longDescription", ready="onReady()")

              br

              label(for='product-notes') Notes
              //input#product-notes.form-control(ng-model="product.notes" type='text', placeholder='Enter notes here')
              // See https://github.com/lemonde/angular-ckeditor
              div(ckeditor="ckeditorOptions", ng-model="product.notes", ready="onReady()")
              br

          // Metadata pane
          #tab-product-metadata.tab-pane
            h4 Metadata, used for SEO
            .form-group
              label(for='product-metaTitle') Title
              input#product-metaTitle.form-control(ng-model="product.metaTitle" type='text', placeholder='metaTitle')
              br

              label(for='product-metaDescription') Description
              input#product-metaDescription.form-control(ng-model="product.metaDescription" type='text', placeholder='')
              br

              label(for='product-metaKeywords') Keywords
              input#product-metaKeywords.form-control(ng-model="product.metaKeywords" type='text', placeholder='')
              br

          #tab-product-variants.tab-pane
            
            div(ng-hide=" !productVariant_showList()")
              #productVariant_listDiv
            div(ng-hide="productVariant_showList()")
              h3
                | {{productVariant_headingForRecordPane}} &nbsp;&nbsp;&nbsp;&nbsp;(pack size {{productVariant_record.components_qty}})
              ul.nav.nav-tabs
                li.active
                  a(href="#tab-productVariant-summary" data-toggle="tab") Summary
                li
                  a(href="#tab-productVariant-details" data-toggle="tab") Details
                li
                  a(href="#tab-productVariant-pricing" data-toggle="tab") Pricing
                li
                  a(href="#tab-productVariant-images" data-toggle="tab") Images
                li
                  a(href="#tab-productVariant-notes" data-toggle="tab") Notes
                li
                  a(href="#tab-productVariant-specs" data-toggle="tab" ng-hide="!haveCurrentVariant()") Specs
                //li
                //  a(href="#tab-productVariant-related" data-toggle="tab" ng-hide="!haveCurrentVariant()") Related
                //li
                //  a(href="#tab-productVariant-supplier" data-toggle="tab" ng-hide="!haveCurrentVariant()") Supplier

              .tab-content.clearfix

                #tab-productVariant-summary.tab-pane.active
                  br
                  #productVariant_summaryDiv

                #tab-productVariant-details.tab-pane
                  br
                  #productVariant_detailsDiv

                #tab-productVariant-pricing.tab-pane

                  //h3 Basic Pricing
                  br
                  .form-group
                    .checkbox
                      label
                        input(type="checkbox" ng-model="productVariant_record.is_free" ng-true-value="1" ng-false-value="0")
                        | This product is free

                  div(ng-hide="productVariant_record.is_free==1")
                    .form-inline
                      .form-group
                        label(for='productVariant-basicPrice') Our price
                        input#productVariant-basicPrice.form-control(ng-model="productVariant_record.last_price" type='text', placeholder='123.45')
                        br
                        //label(for='productVariant-wholesalePrice') Wholesale price
                        //input#productVariant-wholesalePrice.form-control(ng-model="productVariant_record.wholesale_price" type='text', placeholder='123.45')
                        label(for='productVariant-manufacturerPrice') Manufacturer price (RRP)
                        input#productVariant-manufacturerPrice.form-control(ng-model="productVariant_record.manufacturer_price" type='text', placeholder='123.45')

                    br
                    br
                    div(ng-if="productPricing_list.length == 0")
                      .actions-wrap
                        a.btn(ng-click="addPricing_BRKQTY()") Add quantity pricing
                    div(ng-repeat="price in productPricing_list")
                      div(ng-if="price.type == 'BRKQTY'")
                        h3
                          | Additional Rule - Break on Quantity
                          small &nbsp;&nbsp;&nbsp;&nbsp;(\#{{price.pricing_id}})
                        br
                        table.table
                          tr
                            th &nbsp;&nbsp;Qty
                            th &nbsp;&nbsp;Price
                            th
                              | Available for shared sale.
                          tr(ng-repeat="pq in price._pricingQty")
                            td
                              input.form-control(ng-model="pq.quantity", type='number')
                            td
                              input.form-control(ng-model="pq.price", type='number')
                            td.text-center
                              .checkbox-inline
                                input(type="checkbox" ng-model="pq.shared_sale_ok" ng-true-value="1" ng-false-value="0")
                        .actions-wrap
                          a.btn(ng-click="addPricingQty(price)") Add another quantity
                      div(ng-if="price.type == 'DSCAMT'")
                        | Rule {{price.pricing_id}} - Discount by Amount
                      div(ng-if="price.type == 'DSCPCT'")
                        | Rule {{price.pricing_id}} - Discount by Percent

                  //- Components qty
                  //- 1
                  //-
                  //- Last price
                  //- 50
                  //-
                  //- Wholesale price
                  //- 0
                  //-
                  //- Is free


                #tab-productVariant-notes.tab-pane
                  br
                  #productVariant_notesDiv

                #tab-productVariant-related.tab-pane
                  h3 related

                #tab-productVariant-specs.tab-pane
                  br
                  #productVariant_specsDiv

                #tab-productVariant-images.tab-pane
                  br
                  div(ng-repeat="image in productVariantImage_list")
                    .col-md-4
                      img.img-responsive.thumbnail(ng-src="{{image.image_path}}")
                      hr




        //- form-group
      //- col-md-6

    hr
    .actions-wrap
      a.btn(ng-click="product_backButton()") Back to product list
      a.btn(ng-click="productVariant_backButton()" ng-hide="productVariant_showList()") Back to variant list
      a.btn.btn-success(ng-click="productSaveButton()") Save
    //- actions-wrap
  //- card
//- tab-pane



script.

  if (typeof(menuItems) == 'undefined') {
    menuItems = [ ];
  }


  (function(){
    // Private variables
    var productShowList = true;
    const VARIANT_VIEW = 'product_variant';
    const PRICING_VIEW = 'pricing';
    const PRICING_QTY_VIEW = 'pricing_quantity';
    const PV_IMAGE_VIEW = 'product_variant_image';

    var VARIANT_METADATA = null;
    var PRICING_METADATA = null;
    var PRICING_QTY_METADATA = null;
    var PV_IMAGE_METADATA = null;


    /*
     *  Load the list of products that match a filter.
     */
    function loadProducts($scope, context, filter, productId, callback) {
      console.log('loadProducts(' + filter + ', ' + productId + ')');
      
      if (filter && filter.length < 3) {
        $scope.products = [ ];
        return;
      }

      // Check the config
      var protocol = 'http';
      var host = context.TEASERVICE_HOST;
      var port = context.TEASERVICE_PORT;
      var baseUrl = protocol + '://' + host + ':' + port;

      // Load all the categories
      var url = baseUrl + '/philChristmas/product';
      var params = { };
      if (filter) params.filter = filter;
      if (productId) params.productId = productId;
      console.log('url is ' + url);
      console.log('params is ', params);

      // Call the API to get the product details
      // ZZZZ This should use JSONP, as some browsers do not support CORS.
      // ZZZZ Unfortunately JSONP does not support headers, so we need
      // ZZZZ to pass details either in the url or the data. i.e. the
      // ZZZZ server requires changes.
      var req = {
        method: 'POST',
        url: url,
        headers: {
          "access-token": "0613952f81da9b3d0c9e4e5fab123437",
          "version": "2.0.0"
        },
        data: params
      };

      // Prepare the promise, so the caller can use .then(fn) to handle the result.
      var promise = context.$http(req).then(function(response) {
        console.log('success:', response)
        $scope.products = response.data;
        $scope.product = $scope.products[0];

        context.$timeout(function() {
          $scope.$apply();
        }, 100);
        
        if (callback) return callback();
        //return response.data;

      }, function(response) {
        alert('An error occurred calling the TEA API.\nSee the Javascript console for details.')
        console.log('failure:', response)
        console.log('failure:', response.data.message);
      });
    }

    PluginMenuItems.register({
      label: 'Products',
      id: '#tab-product-list',
      init: function(context) {
        var $scope = context.$scope;
        $scope.productVariant_record = null;


        /*
         *  Initialize ckeditor, using angular-ckeditor.
         *  See https://github.com/lemonde/angular-ckeditor
         *  The Toolbar can be configured using the toolbar configurator utility
         *  at bower_components/ckeditor/samples/toolbarconfigurator/index.html
         */
        $scope.ckeditorOptions = {
            language: 'en'
        };
        $scope.ckeditorOptions.toolbarGroups = [
      		{ name: 'clipboard', groups: [ 'clipboard', 'undo' ] },
      		{ name: 'editing', groups: [ 'find', 'selection', 'spellchecker', 'editing' ] },
      		{ name: 'links', groups: [ 'links' ] },
      		{ name: 'insert', groups: [ 'insert' ] },
      		{ name: 'forms', groups: [ 'forms' ] },
      		{ name: 'tools', groups: [ 'tools' ] },
      		{ name: 'document', groups: [ 'mode', 'document', 'doctools' ] },
      		{ name: 'others', groups: [ 'others' ] },
      		{ name: 'basicstyles', groups: [ 'basicstyles', 'cleanup' ] },
      		{ name: 'paragraph', groups: [ 'list', 'indent', 'blocks', 'align', 'bidi', 'paragraph' ] },
      		{ name: 'styles', groups: [ 'styles' ] },
      		{ name: 'colors', groups: [ 'colors' ] },
      		{ name: 'about', groups: [ 'about' ] }
      	];
      	$scope.ckeditorOptions.removeButtons = 'Underline,Subscript,Superscript,Strike,Maximize,Image,Table,HorizontalRule,SpecialChar,Link,Unlink,Anchor,Scayt,PasteFromWord,PasteText,Source,Styles,Format,About,Blockquote';

        /*
         *  When the user enters a search string, search for the product.
         */
        $scope.productFilterChanged = function() {
          loadProducts($scope, context, $scope.productFilter, null);
        }




        /*
         *  Go back to showing the supplier list.
         */
        $scope.product_backButton = function() {
          //alert('back()');
          productShowList = true;
          return false;
        };




        /*
         *  Return true or false, depending on whether we want to
         *  show the supplier list, of a specific supplier details.
         */
        $scope.productShowList = function() {
          return productShowList;
        };


        /*
         *  Select a specific product to show it's details.
         */
        $scope.productSelect = function(productId) {

          // find this product and make it the current supplier
          for (var i = 0; i < $scope.products.length; i++) {
            var p = $scope.products[i];
            if (p.productId == productId) {
              $scope.product = p;
              break;
            }
          }
          $scope.productVariant_record = null;

          // Remember the initial state of the product record.
          $scope.originalProductValues = new OriginalValues();
          $scope.originalProductValues.remember('product', $scope.product);



          // Show the record pane.
          productShowList = false;

          /*
           *  Select the product_variants for this product.
           */
           var params = {
             withReferences: true,
             where: {
               product_id: $scope.product.productId
             }
           }
          TooltwistViews.select(context, VARIANT_VIEW, params, function(err, data, metadata) {
            if (err) {
              console.log('Error selecting view ' + VARIANT_VIEW, err);
              return;
            }
            VARIANT_METADATA = metadata;

            // Use this product variant data
            $scope.productVariant_list = data;
            if ($scope.productVariant_record && $scope.productVariant_record.product_id != $scope.product.productId) {
              $scope.productVariant_record = null;
            }

            console.log('product_variant data=', data);
            console.log('product_variant metadata=', metadata);

            $scope.productVariant_viewLabel = metadata.label;

            // Provide style options for displaying the list and record.
            var displayOptions = {
              //prefix: 'productVariant',
              listModel: 'productVariant_list', // in $scope
              recordModel: 'productVariant_record', // in $scope
              listClickFunction: 'productVariant_listClick', // in $scope
              listTableClasses: 'table-condensed table-hover',
            };

            // Add fields to the DOM for the list
            var fields = TooltwistViews.fieldsForMode(metadata, 'list');
            var html = TooltwistViews.htmlForAngular_list(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var listDiv = $('#productVariant_listDiv');
            listDiv.html(html);
            context.$compile(listDiv)($scope);

            // Add fields to the DOM for the record
            var fields = TooltwistViews.fieldsForMode(metadata, 'record');
            var html = TooltwistViews.htmlForAngular_horizontalDescription(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var recordDiv = $('#productVariant_summaryDiv');
            recordDiv.html(html);
            context.$compile(recordDiv)($scope);

            // Add fields to the DOM for the record
            var fields = TooltwistViews.fieldsForMode(metadata, 'record');
            var html = TooltwistViews.htmlForAngular_edit(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var recordDiv = $('#productVariant_detailsDiv');
            recordDiv.html(html);
            context.$compile(recordDiv)($scope);

            // Add pricing fields to the DOM for the record
            var fields = TooltwistViews.fieldsForMode(metadata, 'pricingTab');
            var html = TooltwistViews.htmlForAngular_edit(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var recordDiv = $('#productVariant_pricingDiv');
            recordDiv.html(html);
            context.$compile(recordDiv)($scope);

            // Add specs fields to the DOM for the record
            var fields = TooltwistViews.fieldsForMode(metadata, 'specsTab');
            var html = TooltwistViews.htmlForAngular_edit(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var recordDiv = $('#productVariant_specsDiv');
            recordDiv.html(html);
            context.$compile(recordDiv)($scope);

            // Add notes fields to the DOM for the record
            var fields = TooltwistViews.fieldsForMode(metadata, 'notesTab');
            var html = TooltwistViews.htmlForAngular_edit(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var recordDiv = $('#productVariant_notesDiv');
            recordDiv.html(html);
            context.$compile(recordDiv)($scope);


            /*// Add notes fields to the DOM for the record
            var fields = TooltwistViews.fieldsForMode(metadata, 'imagesTab');
            var html = TooltwistViews.htmlForAngular_edit(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var recordDiv = $('#productVariant_notesDiv');
            recordDiv.html(html);
            context.$compile(recordDiv)($scope);*/

          });// TooltwistViews.select



        }// productSelect

        /*
         *  Handle a click on the variant list.
         */
        $scope.productVariant_listClick = function(record) {
          //alert('productVariant_listClick')

          // Set the current record.
          // Show the single record pane.
          // Set the label for the pane.
          $scope.productVariant_record = record;
          $scope.productVariant_showListPane = false;
          $scope.productVariant_headingForRecordPane = record.name;

          // Create a store of the json for objects, so we can compare if they've changed and need to be saved.
          // Remember numerics as strings, because they'll be compared later to strings.
          $scope.originalPricingValues = new OriginalValues();
          record.last_price = ''+record.last_price;
          record.wholesale_price = ''+record.wholesale_price;
          record.manufacturer_price = ''+record.manufacturer_price;

          $scope.originalPricingValues.remember('variant-'+record.product_variant_id, record);


          /*
           *  Select the 'pricing' and 'pricing_qty' records for this product variant
           */
           var params = {
             //withReferences: false,
             where: {
               product_variant_id: record.product_variant_id,
               scope: 'V' // On Product Variant
             }
           }
          TooltwistViews.select(context, PRICING_VIEW, params, function(err, data, metadata) {
            if (err) {
              console.log('Error selecting view ' + PRICING_VIEW, err);
              return;
            }

            // Use this product variant data
            // We'll display these manually, so don't need metadata
            PRICING_METADATA = metadata;
            console.log('pricing data=', data);
            $scope.productPricing_list = data;

            // Remember the original values
            $scope.productPricing_list.forEach(function(pricing) {
              var key = 'pricing-' + pricing.pricing_id;
              $scope.originalPricingValues.remember(key, pricing);
            });


            // Get the pricing_ids for any 'break quantity' pricing rules.
            var pricing_id = '';
            var sep = '';
            $scope.productPricing_list.forEach(function(price) {
              if (price.type == 'BRKQTY') {
                pricing_id += sep + price.pricing_id;
                sep = ',';
                price._pricingQty = [ ];
              }
            });
            if (pricing_id == '') {

              // There are no 'break quantity' pricing records, so tell angular we are done.
              return context.$timeout(function(){ $scope.$apply(); }, 10);
            } else {

              /*
               *  Load the pricing_qty records for the 'break quantity' pricing records.
               */
              TooltwistViews.select(context, PRICING_QTY_VIEW, { where:{ pricing_id: pricing_id } }, function(err, data, metadata) {
                if (err) {
                  console.log('Error selecting view ' + PRICING_QTY_VIEW, err);
                  return;
                }
                PRICING_QTY_METADATA = metadata;
                console.log('pricing_quantity selected' , data);
                
                
                // Patch the pricing_qty records ointo the pricing records.
                var pricingQty_list = data;
                pricingQty_list.forEach(function(pq) {
                  // Find the pricing record. The list is usually one long, so we can be lazy.
                  $scope.productPricing_list.forEach(function(price) {
                    if (price.pricing_id == pq.pricing_id) {
                      price._pricingQty.push(pq);
                    }
                  });
                });// next pq


                // Remember the original pricing_quantity values
                $scope.productPricing_list.forEach(function(pricing) {
                  pricing._pricingQty.forEach(function(pq) {
                    var key = 'pricingQty-' + pq.pricing_quantity_id;
                    $scope.originalPricingValues.remember(key, pq);
                  });
                });


                // Finished - tell Angular we are done.
                return context.$timeout(function(){ $scope.$apply(); }, 10);
              });
            }

            //console.log('pricing metadata=', metadata);




            //$scope.productVariant_viewLabel = metadata.label;

            // Provide style options for displaying the list and record.
            /*var displayOptions = {
              //prefix: 'productVariant',
              listModel: 'productVariantImage_list', // in $scope
              //recordModel: 'productVariantImage_record', // in $scope
              //listClickFunction: 'productVariant_listClick', // in $scope
              //listTableClasses: 'table-condensed table-hover',
            };

            // Add fields to the DOM for the list
            var fields = TooltwistViews.fieldsForMode(metadata, 'list');
            var html = TooltwistViews.htmlForAngular_list(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var listDiv = $('#productVariantImage_listDiv');
            listDiv.html(html);
            context.$compile(listDiv)($scope);*/

          });// select



          /*
           *  Select the product_variant_image records for this product_variant.
           */
          TooltwistViews.select(context, PV_IMAGE_VIEW, {
            withReferences: false,
            where: {
              product_variant_id: record.product_variant_id
            }
          }, function(err, data, metadata) {
            if (err) {
              console.log('Error selecting view ' + PV_IMAGE_VIEW, err);
              return;
            }
            PV_IMAGE_METADATA = metadata;

            // Use this product variant data
            $scope.productVariantImage_list = data;
            /*if ($scope.productVariant_record && $scope.productVariant_record.product_id != $scope.product.productId) {
              $scope.productVariant_record = null;
            }*/

            console.log('product_variant_image data=', data);
            console.log('product_variant_image metadata=', metadata);

            //$scope.productVariant_viewLabel = metadata.label;

            // Provide style options for displaying the list and record.
            var displayOptions = {
              //prefix: 'productVariant',
              listModel: 'productVariantImage_list', // in $scope
              //recordModel: 'productVariantImage_record', // in $scope
              //listClickFunction: 'productVariant_listClick', // in $scope
              //listTableClasses: 'table-condensed table-hover',
            };

            // Add fields to the DOM for the list
            var fields = TooltwistViews.fieldsForMode(metadata, 'list');
            var html = TooltwistViews.htmlForAngular_list(metadata, fields, displayOptions);
            // Update the DOM and get Angular to bind our new DOM elements onto it's models.
            var listDiv = $('#productVariantImage_listDiv');
            listDiv.html(html);
            context.$compile(listDiv)($scope);

          });// select
        }// productVariant_listClick


        /*
         *  Go back to showing the supplier list.
         */
        $scope.productVariant_backButton = function() {
          //alert('back()');
          $scope.productVariant_record = null;
          $scope.productVariant_showListPane = true;
          return false;
        };// productVariant_backButton


        /*
         *  Save the product details.
         */
        $scope.productSaveButton = function() {
          console.log('productSaveButton()');



          checkProduct(function(err) {
            if (err) {
              alert('Error saving product details.');
              return;
            }

            alert('save complete');
          });
        };



        function checkProduct(callback/*(err)*/) {
          console.log('checkProduct()');

                    // See if the product has changed
          var product = $scope.product;
          var key = 'product';
          if ($scope.originalProductValues.changed(key, $scope.product)) {
            console.log('product has changed.')
            return checkProductVariant(callback);
          } else {
            console.log('product has NOT changed');
            return checkProductVariant(callback);
          }
        }



        function checkProductVariant(callback/*(err)*/) {
          console.log('checkProductVariant()');

          // See if the product_variant has changed.
          var variant = $scope.productVariant_record;
          if (!variant) {
            console.log('no variant selected yet')
            return;
          }
          console.log('price ' + typeof(variant.last_price));
          /*try {
            variant.last_price = variant.last_price;
            variant.wholesale_price = variant.wholesale_price;
            variant.manufacturer_price = variant.manufacturer_price;
          } catch (e) {
            alert('Invalid price');
          }*/
          var key = 'variant-' + variant.product_variant_id;
          if ($scope.originalPricingValues.changed(key, variant)) {
            console.log('product variant has changed.')

            // Save the product_variant
            var saverec = $scope.originalPricingValues.clone(variant);
            //delete saverec.product_id__desc;
            console.log('saving ', saverec);
            TooltwistViews.save(context, VARIANT_METADATA, 'record', saverec, function(err, reply) {              
              console.log('save returned', err, reply);
              if (err) {
                console.log('Error saving view ' + VARIANT_VIEW, err);
                return;
              }

              if (reply.data.newId) {
                variant.product_variant_id = reply.data.newId;
                /*pricing._pricingQty.forEach(function(pq) {
                  pq.pricing_id = reply.data.newId;
                });*/
              }
              $scope.originalPricingValues.remember('variant-'+variant.product_variant_id, variant);
              return checkPricing(callback);
            });
          } else {
            console.log('product_variant has NOT changed.')
            return checkPricing(callback);
          }
        }



        function checkPricing(callback/*(err)*/) {
          console.log('checkPricing()');

          // See if the pricing records have changed.
          /*$scope.productPricing_list.forEach(function(pricing) {
            if (
              !pricing.pricing_id
              ||
              $scope.originalPricingValues.changed('pricing-'+pricing.pricing_id, pricing)
            ) {
              alert('pricing has changed.')
              return checkPricingQty(callback);
            }
            alert('pricing NOT changed.')
            return checkPricingQty(callback);
          });// next pricing*/


          (function nextPricing(index) {

            console.log('nextPricing(' + index + ')');
            if (index >= $scope.productPricing_list.length) {
              return checkPricingQty(callback);
            }

            // Has this pricing_quantity record changed, or maybe it's new?
            var pricing = $scope.productPricing_list[index];
            if (
              !pricing.pricing_id
              ||
              $scope.originalPricingValues.changed('pricing-'+pricing.pricing_id, pricing)
            ) {

              // Save the pricing_quantity
              alert('pricing has changed.');
              var saverec = $scope.originalPricingValues.clone(pricing);
              console.log('saving ', saverec);
              TooltwistViews.save(context, PRICING_METADATA, 'record', saverec, function(err, reply) {
                if (err) {
                  console.log('Error saving view ' + PRICING_VIEW, err);
                  return;
                }
                console.log('save returned', err, reply);
                if (reply.data.newId) {
                  pricing.pricing_id = reply.data.newId;
                  pricing._pricingQty.forEach(function(pq) {
                    pq.pricing_id = reply.data.newId;
                  });
                }
                $scope.originalPricingValues.remember('pricing-'+pricing.pricing_id, pricing);

                return nextPricing(index + 1);
              });
            } else {

              // No change to this record.
              console.log('pricing NOT changed.');
              return nextPricing(index + 1);
            }

          })(0); // Start iterating nextPricingQty


        }



        function checkPricingQty(callback/*(err)*/) {
          console.log('checkPricingQty()');

          // See if the pricing_quantity records have changed
          var pricingQtyList = [ ];
          $scope.productPricing_list.forEach(function(pricing) {
            pricing._pricingQty.forEach(function(pq) {
              pricingQtyList.push(pq);
            });
          });// next pricing

          (function nextPricingQty(index) {

            console.log('nextPricingQty(' + index + ')');
            if (index >= pricingQtyList.length) {
              return callback(null);
            }

            // Has this pricing_quantity record changed, or maybe it's new?
            var pq = pricingQtyList[index];
            if (
              !pq.pricing_quantity_id
              ||
              $scope.originalPricingValues.changed('pricingQty-'+pq.pricing_quantity_id, pq)
            ) {

              // Save the pricing_quantity
              console.log('pricingQty has changed. ' + pq.quantity);
              var saverec = $scope.originalPricingValues.clone(pq);
              console.log('saving ', saverec);
              TooltwistViews.save(context, PRICING_QTY_METADATA, 'record', saverec, function(err, reply) {
                console.log('save returned', err, reply);
                if (err) {
                  console.log('Error selecting view ' + PRICING_QTY_VIEW, err);
                  return;
                }
                
                if (reply.data.newId) {
                  pq.pricing_quantity_id = reply.data.newId;
                }
                $scope.originalPricingValues.remember('pricingQty-'+pq.pricing_quantity_id, pq);

                return nextPricingQty(index + 1);
              });
            } else {

              // No change to this record.
              console.log('pricingQty NOT changed. ' + pq.quantity);
              return nextPricingQty(index + 1);
            }

          })(0); // Start iterating nextPricingQty
        }// checkPricingQty



        /*
         *  Save the supplier details.
         * /
        $scope.productVariant_saveButton = function() {
          alert('productVariant_saveButton()');
          //var fields = TooltwistViews.fieldsForMode(metadata, 'record');
          //TooltwistViews.save(context, viewName, fields, $scope.generic_record, function(err, reply) {
          //  console.log('returned', err, reply);
          //});
        }// productVariant_saveButton
        */


        /*
         *  Return true when we want to show the list (rather than the record).
         */
        $scope.productVariant_showList = function() {
          return $scope.productVariant_showListPane;
        }// productVariant_showList


        /*
         *  Return true when we want to show the tabs for a variant.
         */
        $scope.haveCurrentVariant = function() {
          if ($scope.productVariant_record) {
            //console.log('HAVE current variant')
            return true;
          } else {
            //console.log('NO current variant')
            return false;
          }
        }

        /*
         *  Add a new pricing_quantity record to the pricing rule.
         */
        $scope.addPricingQty = function(pricing) {
          var rec = {
            pricing_id: pricing.pricing_id,
            quantity: 2,
            price: $scope.productVariant_record.last_price,
            shared_sale_ok: 1,
            multiple_addresses_ok: 1
          };
          // Work out a new qty/price
          try {
            pricing._pricingQty.forEach(function(pq) {
              if (pq.price < rec.price) {
                rec.price = pq.price;
              }
              if (parseInt(pq.quantity) > parseInt(rec.quantity)) {
                rec.quantity = pq.quantity + 5;
              }
            });
          } catch (e) {}
          pricing._pricingQty.push(rec);
        }

        /*
         *  Add a pricing record for 'quantity breakpoint' pricing.
         */
        $scope.addPricing_BRKQTY = function() {
          var rec = {
            /*allow_picked_up: 0,*/
            /*amount: null,
            amount_exceed: null,
            */
            code: '',
            /*
            created_at: null,
            created_by: null,
            description: null,
            end_at: null,
            item_scope: null,
            modified_at: null,
            modified_by: null
            new_order_only: 0,*/
            //pricing_id: 1,
            //product_id: null,
            product_variant_id: $scope.productVariant_record.product_variant_id,
            quantity: 1,
            //reserved: 0,
            //role_id: null,
            scope: "V",
            //start_at: null,
            status: "A",
            store_id: context.STORE_ID,
            type: "BRKQTY",
            /*unlimited: 1,
            used: 0,*/
            _pricingQty: [ {
              //pricing_id: pricing.pricing_id,
              quantity: 2,
              price: $scope.productVariant_record.last_price,
              shared_sale_ok: 1,
              multiple_addresses_ok: 1
            } ],
          };
          console.log('new pricing record', rec);
          $scope.productPricing_list.push(rec);
        }

      }, // init()

      /*
       *  Activate this menu option programmatically.
       */
      activate: function(context, data) {
        productShowList = false;
        context.$scope.productVariant_showListPane = true;
        loadProducts(context.$scope, context, null, data.productId, function() {
          context.$scope.productSelect(data.productId);
        });        
      },

      /*
       *  When we switch menu option, we want to come back to the list.
       */
      reset: function(context) {
        var $scope = context.$scope;
        var $timeout = context.$timeout;

        // This function might or might not have been called by Angular. The
        // timeout function causes Angular to $apply() changes to the model,
        // and also allows the current function to return, if it was called
        // by Angular (for example, during page initialization), preventing
        // and Angular $proc (???) error.
        context.$timeout(function() {
          productShowList = true;
          $scope.productVariant_showListPane = true;
        }, 10);
      },

      nocomma: null
    });

  })();


  function OriginalValues() {
    console.log('OriginalValues()')
    var hashtable = [ ]; // name -> json

    return {

      // Remember an object returned by the API
      remember: function(name, object) {
        console.log('OriginalValues.remember', name, object);
        hashtable[name] = this.clone(object);
      },// remember

      // Create a clone, without system properties.
      clone: function(object) {
        var newobj = { };
        for (var property in object) {
          if (
            object.hasOwnProperty(property)
            && !property.startsWith('_')
            && !property.startsWith('$')
            && !property.endsWith('__desc')
          ) {
            newobj[property] = object[property];
          }
        }
        //console.log('newobj=', newobj);
        return newobj;
      },

      // See if this object matches the original
      changed: function(name, object) {
        console.log('OriginalValues.changed', name);
        if (!object) {
          return false; // Object does not exist
        }

        var original = hashtable[name];
        if (!original) {
          console.log('    NEW OBJECT');
          return true; // New object
        }

        // Compare against the original
        for (var property in original) {
          var changed = false;
          if (object[property] !== original[property]) {
            console.log('----------------------------------------------------------------');
            console.log(name + ': property ' + property + ' has changed.');
            console.log('  ORIGINAL:', original[property]);
            console.log('       NEW:', object[property]);
            //return true; // Property has changed
            changed = true;
          }
          if (changed) return true;
        }
        console.log('    NOT CHANGED');
        return false;
      }// changed

    }; // returned object
  } // OriginalValues
