'use strict';

/**
 * Create the empty modules along with their dependencies
 */ 

/**
 * Any functionality that is shared across modules should be created in shared
 */
angular.module('shared', ['ngResource', 'ngAnimate', 'ui.bootstrap', 'appConfiguration'])
    .config(['$provide', '$httpProvider', 'siteConfigurationProvider', function($provide, $httpProvider, siteConfigurationProvider) {

            var constants = siteConfigurationProvider.$get();

            if (constants && constants.disableLocationServices) {
                $provide.decorator('$location', [
                    '$delegate', '$browser', function($delegate, $browser) {
                        $delegate.absUrl = function() {
                            return $browser.url();
                        };
                        return $delegate;
                    }
                ]);
            }

            if (constants && constants.disableAjaxRequestCache) {

                //initialize get if not there
                if (!$httpProvider.defaults.headers.get) {
                    $httpProvider.defaults.headers.get = {};
                }

                // Answer edited to include suggestions from comments
                // because previous version of code introduced browser-related errors

                //disable IE ajax request caching
                $httpProvider.defaults.headers.get['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT';
                // extra
                $httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
                $httpProvider.defaults.headers.get['Pragma'] = 'no-cache'; // jshint ignore:line
            }
        }
    ]);


/**
 * The address module allows creating different address inputs based on the country.
 */
angular.module('address', []);

/**
 * whishList allows to add item to wishList
 */
angular.module('wishList', ['shared']);

/**
 * product allows end customers to check product details
 */
angular.module('product', ['wishList']);

/**
 * The cart allows end customers to track products they are going to purchase
 */
angular.module('cart', ['product']);

/**
 * Create module named "account"
 */
angular.module('account', ['shared', 'address']);

/**
 * Checkout allows end customers to take the items in their cart, pay for them and create the order
 */
angular.module('checkout', ['cart', 'account']);

/**
 * Confirm allows end customers to view their order confirmation after order was successfully processed.
 */
angular.module('confirm', ['cart']);

/**
 * Create module named "website". The module allows for access to website data such as ID and currency symbol
 */
angular.module('website', []);
;
'use strict';

/**
* This filter is responsible for rendering html properties of the model
*/
angular.module('shared').filter('odHtmlUnsafe', ['$sce', function ($sce) {
    return function (val) {
        return $sce.trustAsHtml(val);
    };
}]);
;
/*exported openSpinner, closeSpinner */
/*global GlobalConstants:false */
'use strict';

//Loading Spinner Scripts
function openSpinner(text) {

    //Move to the top of page
    scroll(0, 0);

    var gc = new GlobalConstants({});
    var spinnermodalId = gc.spinnermodalId;
    var spinnerfadeId = gc.spinnerfadeId;
    var spinnertextId = gc.spinnertextId;

    if (text != window.undenfined) {
        document.getElementById(spinnertextId).innerHTML = text;
        document.getElementById(spinnermodalId).className = 'spinnerWithText';
    } else {
        document.getElementById(spinnermodalId).className = 'spinnerNoText';
    }

    document.getElementById(spinnermodalId).style.display = 'block';
    document.getElementById(spinnerfadeId).style.display = 'block';

}

function closeSpinner() {
    var gc = new GlobalConstants({});
    var spinnermodalId = gc.spinnermodalId;
    var spinnerfadeId = gc.spinnerfadeId;
    var spinnertextId = gc.spinnertextId;

    document.getElementById(spinnermodalId).style.display = 'none';
    document.getElementById(spinnerfadeId).style.display = 'none';
    document.getElementById(spinnertextId).innerHTML = '';

}


;
/*global openSpinner:false */
/*global closeSpinner:false */
'use strict';

angular.module('shared').factory('spinnerFactory', 
       function () {

           return {
                show: openSpinner,
                hide: closeSpinner
            };
        }

);;
'use strict';

angular.module('shared').directive('odBlinkElement', ['$animate', '$timeout', function ($animate, $timeout) {
    return function(scope, element, attrs) {
        scope.$watch(attrs.odBlinkElement, function() {
            $animate.addClass(element, 'fade-in');
            $timeout(function() {
                $animate.removeClass(element, 'fade-in');
            }, scope.blinkLag);

        });
    };
}]);;
/*global GlobalConstants:false */
'use strict';

/* This provides constants to the client code and is injected into platform angular module
from the appConfiguration provider 

This should not be changed until you discuss with the platform team or you may risk breaking 
all client side constants.
*/
angular.module('appConfiguration', [])
.provider('siteConfiguration', 
   function () {

       return {
           $get: function () {
               //this is default platform implementation - do not override anything
               return new GlobalConstants({});
           }
       };
   }
);;
'use strict';

angular.module('shared')
.provider('appUrlBuilder',
   function () {

       var builder = function (siteConfiguration) {
           return {
               buildUrl: function (key) {
                   return siteConfiguration.rootUrl + siteConfiguration[key];
               },
               buildTemplateUrl: function (key) {
                   return siteConfiguration.rootUrl + siteConfiguration[key];
               },
               buildUniqueTemplateUrl: function(key) {
                   //Bug 19856: adding a time string at the end to trick IE so it call back every time
                   //Fixed by change set 47733
                   return siteConfiguration.rootUrl + siteConfiguration[key];
               }
           };
       };

       return {
           $get: ['siteConfiguration', function (siteConfiguration) {
               return builder(siteConfiguration);
           }]
       };
   }
);;
/*global GlobalLocalization:false */
'use strict';

angular.module('shared').provider('siteRes',
    function() {
        return {
            $get: function() {
                return new GlobalLocalization({});
            }
        };
    });;
'use strict';

angular.module('shared').provider('siteCulture',
    function () {
        return {
            $get: function () {
                return {
                    currentCulture: ''
                };
            }
        };
    });;
'use strict';

/**
 * This is the helper service that wraps bootstrap dialog, so that dialog can be used in Angular
  */

angular.module('shared').factory('DialogService',
    function() {
        return window.BootstrapDialog;
    });
;
'use strict';

/**
 * This is the helper service that is responsible for page navigation
  */

angular.module('shared').factory('NavigationService', ['$window',
    function ($window) {
        
        var navigate = function (url) {
            $window.location.href = url;
        };

        return {
            navigate: navigate
        };

    }]);
;
'use strict';

angular.module('shared').provider('AppObserver',
    function() {

        var observer = function($rootScope) {
            return {
                subscribe: function(eventName, $scope, handler) {
                    return $scope.$on(eventName, function(event, message) {
                        handler(message);
                    });
                },
                broadcast: function(eventName, message) {
                    $rootScope.$broadcast(eventName, message);
                }
            };
        };

        return {
            $get: ['$rootScope', function($rootScope) {
                return observer($rootScope);
            }]
        };
    });;
'use strict';

angular.module('shared')
    // Path: /error/404
    .controller('Error404Ctrl', ['$scope', '$location', '$window', function ($scope, $location, $window) {
        $scope.$on('$viewContentLoaded', function () {
            $window.ga('send', 'pageview', { 'page': $location.path(), 'title': $scope.$root.title });
        });
    }]);;
'use strict';

angular.module('shared').provider('appLogger',
    function () {

        function Logger() {
            var offStateChangeStart;
            var offStateChangeError;
            var offStateChangeSuccess;
            var offViewContentLoaded;
            var offstateNotFound;
            var offRouteChangeStart;

            this.activate = function($rootScope) {

                // The following parameters are available to the event handler signature: event, toState, toParams, fromState, fromParams
                offStateChangeStart = $rootScope.$on('$stateChangeStart', function(event, toState, toParams) {
                    console.log('$stateChangeStart to ' + toState.to + '- fired when the transition begins. toState,toParams : \n', toState, toParams);
                });

                // The following parameters are available to the event handler signature: event, toState, toParams, fromState, fromParams
                offStateChangeError = $rootScope.$on('$stateChangeError', function () {
                    console.log('$stateChangeError - fired when an error occurs during transition.');
                    console.log(arguments);
                });

                // The following parameters are available to the event handler signature: event, toState, toParams, fromState, fromParams
                offStateChangeSuccess = $rootScope.$on('$stateChangeSuccess', function (event, toState) {
                    console.log('$stateChangeSuccess to ' + toState.name + '- fired once the state transition is complete.');
                });

                offViewContentLoaded = $rootScope.$on('$viewContentLoaded', function(event) {
                    console.log('$viewContentLoaded - fired after dom rendered', event);
                });

                offstateNotFound = $rootScope.$on('$stateNotFound', function(event, unfoundState, fromState, fromParams) {
                    console.log('$stateNotFound ' + unfoundState.to + '  - fired when a state cannot be found by its name.');
                    console.log(unfoundState, fromState, fromParams);
                });

                // The following parameters are available to the event handler signature: event, next, current
                offRouteChangeStart = $rootScope.$on('$routeChangeStart', function () {
                    console.log('$routeChangeStart');
                    console.log(arguments);
                });
            };

            this.deactivate = function() {
                offStateChangeStart();
                offStateChangeError();
                offStateChangeSuccess();
                offViewContentLoaded();
                offstateNotFound();
                offRouteChangeStart();
            };
        }

        this.$get = function() {
            return new Logger();
        };
    }
);;
'use strict';

/**
 * Responsible for store address related data and passing between controllers
 */
angular.module('shared').factory('AddressDataHelper', 
    function () {

        var addressData = {};
        addressData.shippingData = {};
        addressData.billingData = {};
        addressData.sameAsShippingAddress = true;
        return {
            updateShippingData: function (data) {
                addressData.shippingData = data;
            },
            updateBillingData: function (data) {
                addressData.billingData = data;
            },
            updateSameAsShippingAddress: function (data) {
                addressData.sameAsShippingAddress = data;
            },
            getShippingData: function () {
                return addressData.shippingData;
            },
            getBillingData: function () {
                return addressData.billingData;
            },
            getSameAsShippingAddress: function () {
                return addressData.sameAsShippingAddress;
            }

    };
    }
);;
'use strict';

/**
* This directive shows form validation error messages.
*/

angular.module('shared').directive('odValidationMessage', function () {
    return {
        restrict: 'A',
        require: '^form',
        template: '<span ng-show="shouldShow()"><span ng-transclude></span></span>',
        scope: {
            inputName: '@'
        },
        transclude: true,
        link: function(scope, element, attrs, formCtrl) {

            scope.shouldShow = function() {
                return formCtrl.$dirty && formCtrl.$invalid &&
                    formCtrl[scope.inputName] && formCtrl[scope.inputName].$dirty && formCtrl[scope.inputName].$invalid;
            };
        }
    };

});;
'use strict';

/**
* This directive is show errors on the page.
*/
angular.module('shared').directive('odShowErrors', ['AppObserver', function (appObserver) {
    return {
        restrict: 'A',
        require: '^form',
        link: function (scope, el, attrs, formCtrl) {
            // find the text box element, which has the 'name' attribute
            var inputEl = el[0].querySelector('[name]');
            // convert the native text box element to an angular element
            var inputNgEl = angular.element(inputEl);
            // get the name on the text box so we know the property to check
            // on the form controller
            var inputName = inputNgEl.attr('name');
            // only apply the has-error class after the user leaves the text box
            inputNgEl.bind('blur', function () {
                el.toggleClass('has-error', formCtrl[inputName].$invalid);
            });
            var showErrorsListener = appObserver.subscribe('show-errors-check-validity', scope, function (formName) {

                if (formCtrl.$name === formName && !(typeof inputName === 'undefined' || inputName === undefined)) {
                    el.toggleClass('has-error', formCtrl[inputName].$invalid);
                }
            });

            //Unbind listeners when scope is destroyed
            scope.$on('$destroy', function () {
                showErrorsListener();
                el.remove();
            });
        }
    };
}]);;
'use strict';

/**
 * This is the helper service that provides all sort of useful operations.
 */
angular.module('shared').factory('AppHelper', ['siteConfiguration', function (siteConfiguration) {

    var mergeObjects = function (object1, object2) {
        for (var attrname in object2) {
            if (object2.hasOwnProperty(attrname)) {
                object1[attrname] = object2[attrname];
            }
        }
    };

    var objectToKeyValuePairArray = function(object) {
        var result = [];

        for (var o in object) {
            if (object.hasOwnProperty(o)) {
                var value = object[o];

                //array
                if (Object.prototype.toString.call(value) === '[object Array]') {
                    value = value.join(siteConfiguration.delimiter);
                }

                var d = { Key: o, Value: value };
                result.push(d);
            }
        }

        return result;
    };

    var setFormDirty = function(form) {
        if (form.$pristine) {
            form.$setDirty();

            for (var p in form) {
                if (form.hasOwnProperty(p)) {
                    if (form[p].$invalid === true && form[p].$pristine === true) {
                        //make input dirty
                        form[p].$setViewValue(form[p].$viewValue);
                    }
                }
            }
        }
    };

    return {
        mergeObjects: mergeObjects,
        objectToKeyValuePairArray: objectToKeyValuePairArray,
        setFormDirty: setFormDirty
    };
}]);;
/*exported EvaluateThreeDSResult */
'use strict';

//Will use to access angular checkoutCtrl for HPCI and 3Ds
var getCheckoutScope = function () {
    var scope = angular.element(document.getElementById('appCheckout')).scope();
    var ccScope = '';
    if (scope !== null && scope !== '' && scope !== undefined) {
        for (var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
            if (cs.identityName !== undefined && cs.identityName === 'CheckoutCtrl') {
                ccScope = cs;
                break;
            }
        }
    }
    return ccScope;
};

var EvaluateThreeDSResult = function () {
    var cCtrl = getCheckoutScope();

    cCtrl.$apply(function () {
        cCtrl.verify3Ds();
    });
};;
'use strict';

/**
 * Responsible for all website data specific communication with the server
 */

angular.module('shared').factory('WebsiteDataService', [
    '$resource', 'appUrlBuilder',
    function ($resource, appUrlBuilder) {
        var resource = $resource(appUrlBuilder.buildUrl('websiteApiUrl'), null,
        {
            'getWebsiteData': { method: 'GET', url: appUrlBuilder.buildUrl('getWebsiteData'), isArray: false, responseTypw: 'json' } 
        });

        return {
            getWebsiteData: function () {
                var data = resource.getWebsiteData();
                return data;
            }
        };
    }
]);;
'use strict';

/**
 * Provides a global storage for site data, such as (overridden) currency formatting information and ID
 */

angular.module('shared').factory('WebsiteDataStorageService', ['$q', 'WebsiteDataService',
    function ($q, websiteDataSvc) {
        var websiteData = { Id: 0, Currency: { Symbol: '', DecimalSeparator : '', GroupSize:'', NegativePrefix : '',NegativeSuffix:'',PositivePrefix:'',PositiveSuffix:'' } };
        var loadWebsiteData = function () {
            var deferred = $q.defer();
            websiteDataSvc.getWebsiteData().$promise.then(
                function (data) {
                    sync(data, false);
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });
            return deferred.promise;
        };

        var sync = function(data) {
            websiteData.Id = data.Id;
            websiteData.Currency.Symbol = data.Currency.Symbol;
            websiteData.Currency.DecimalSeparator = data.Currency.DecimalSeparator;
            websiteData.Currency.GroupSeparator = data.Currency.GroupSeparator;
            websiteData.Currency.GroupSize = data.Currency.GroupSize;
            websiteData.Currency.NegativePrefix = data.Currency.NegativePrefix;
            websiteData.Currency.NegativeSuffix = data.Currency.NegativeSuffix;
            websiteData.Currency.PositivePrefix = data.Currency.PositivePrefix;
            websiteData.Currency.PositiveSuffix = data.Currency.PositiveSuffix;
        };

        loadWebsiteData();

        return {
            websiteData: websiteData
        };

    }]);;
'use strict';

/**
 * Responsible for manipulations of locale service for using custom patterns, e.g. custom currency patterns for the current website
 */

angular.module('shared').factory('LocaleService', [ '$locale', 'WebsiteDataStorageService',
    function ($locale, websiteDataStorageService) {

        // Provides a temporary storage for locale pattern values. Must be expanded as needed.
        var localeBackup = function() {

            var currecySymbol, decimalSeparator, groupSeparator, groupSize, negativePrefix, negativeSuffix, positivePrefix, positiveSuffix;

            // Stores locale patterns
            var store = function() {
                currecySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
                decimalSeparator = $locale.NUMBER_FORMATS.DECIMAL_SEP;
                groupSeparator = $locale.NUMBER_FORMATS.GROUP_SEP;
                groupSize = $locale.NUMBER_FORMATS.PATTERNS[1].gSize;
                negativePrefix = $locale.NUMBER_FORMATS.PATTERNS[1].negPre;
                negativeSuffix = $locale.NUMBER_FORMATS.PATTERNS[1].negSuf;
                positivePrefix = $locale.NUMBER_FORMATS.PATTERNS[1].posPre;
                positiveSuffix = $locale.NUMBER_FORMATS.PATTERNS[1].posSuf;
            };

            // Restores locale patterns
            var restore = function() {
                $locale.NUMBER_FORMATS.CURRENCY_SYM = currecySymbol;
                $locale.NUMBER_FORMATS.DECIMAL_SEP = decimalSeparator;
                $locale.NUMBER_FORMATS.GROUP_SEP = groupSeparator;
                $locale.NUMBER_FORMATS.PATTERNS[1].gSize = groupSize;
                $locale.NUMBER_FORMATS.PATTERNS[1].negPre = negativePrefix;
                $locale.NUMBER_FORMATS.PATTERNS[1].negSuf = negativeSuffix;
                $locale.NUMBER_FORMATS.PATTERNS[1].posPre = positivePrefix;
                $locale.NUMBER_FORMATS.PATTERNS[1].posSuf = positiveSuffix;
            };

            return {
                Store: store,
                Restore: restore
            };
        };

        // Overwrite locale provider's currency formatting information with overridden culture info for currency
        var setCustomPatterns = function() {
            $locale.NUMBER_FORMATS.CURRENCY_SYM = websiteDataStorageService.websiteData.Currency.Symbol;
            $locale.NUMBER_FORMATS.DECIMAL_SEP = websiteDataStorageService.websiteData.Currency.DecimalSeparator;
            $locale.NUMBER_FORMATS.GROUP_SEP = websiteDataStorageService.websiteData.Currency.GroupSeparator;
            $locale.NUMBER_FORMATS.PATTERNS[1].gSize = websiteDataStorageService.websiteData.Currency.GroupSize;
            $locale.NUMBER_FORMATS.PATTERNS[1].negPre = websiteDataStorageService.websiteData.Currency.NegativePrefix;
            $locale.NUMBER_FORMATS.PATTERNS[1].negSuf = websiteDataStorageService.websiteData.Currency.NegativeSuffix;
            $locale.NUMBER_FORMATS.PATTERNS[1].posPre = websiteDataStorageService.websiteData.Currency.PositivePrefix;
            $locale.NUMBER_FORMATS.PATTERNS[1].posSuf = websiteDataStorageService.websiteData.Currency.PositiveSuffix;
        };

        return {
            // This method
            SetCustomLocale: function () {
                var storage = localeBackup();
                storage.Store();
                setCustomPatterns();
                return storage;
            },
            RestoreLocale: function(storage) {
                storage.Restore();
            }
        };
    }
]);;
'use strict';

/**
* This filter is responsible for rendering a currency with website's specific currency symbol
* The filter uses the overridden currency formatting provided by website data service to format the currency.
*/

angular.module('shared').filter('odCurrency', ['$filter', 'LocaleService',
    function ($filter, localeService) {

        return function (value) {
            var storage = localeService.SetCustomLocale();
            var formattedValue = $filter('currency')(value);
            localeService.RestoreLocale(storage);
            return formattedValue;
        };
    }
]);;
'use strict';
// sum object numberic fields: name: 
// exp: {{giftCards | sumNumberFilter:'Amount'}}
// sum giftCards Amount fields
angular.module('shared').filter('sumNumberFilter', [function () {
    return function (items, numericFieldName) {
        var totalAmount = 0;

        angular.forEach(items, function (item) {
            totalAmount += Number(item[numericFieldName]);
        });

        return totalAmount;
    };
}]);
;
angular.module('shared').directive('odImageOnLoad', function () {
    return {
        restrict: 'A',
        scope: {
            onLoad: '&'
        },
        priority: 0,
        link: function (scope, element) {
            element.bind('load', function () {
                scope.onLoad();
            });
        }
    };
});;
angular.module('shared').directive('odNumberOnly', function () {
 
    return {
        restrict: 'A',
        require: 'ngModel',
        priority: 0,
        link: function (scope, element, attrs, modelCtrl) {
        
            modelCtrl.$parsers.push(function (inputValue) {
              
              
                if (inputValue === undefined || inputValue === null) {
                    return '';
                }
                var transformedInput = inputValue.replace(/[^0-9]/g, '');
              
                if (parseInt(transformedInput) > 2000000000) {
                    transformedInput = '2000000000';
                    inputValue = '2000000000';
                }
                if (transformedInput != inputValue) {
                    
                    modelCtrl.$setViewValue(transformedInput);
                    modelCtrl.$render();
                }

                return transformedInput;
            });
        }
    };
});

;
'use strict';

/**
 * jQuery service provider
  */

angular.module('shared').factory('jQueryService', ['$window',
    function ($window) {

        return $window.jQuery;

    }]);
;
'use strict';
/* Fix IE8 AngularJS script cache problem
*/
angular.module('shared').directive('cachedTemplate', ['$templateCache', function ($templateCache) {
    'use strict';
    return {
        restrict: 'A',
        terminal: true,
        replace: true,
        compile: function (element, attr) {
            if (attr.type === 'text/ng-template') {
                var templateUrl = attr.cachedTemplate,
                 text = element.html();
                $templateCache.put(templateUrl, text);
            }
        }
    };
}]);;
/*global StoreInventory:false */
'use strict';

/**
 *  This is the service that provides storeLocator implementation
  */

angular.module('shared').factory('StoreInventoryService', ['StoreLocatorService', 'siteConfiguration', 'siteRes',
    function (storeLocatorService, siteConfiguration, siteRes) {

        return new StoreInventory(storeLocatorService, siteConfiguration, siteRes);

    }]);;
/*global StoreLocator:false */
'use strict';

/**
 *  This is the service that provides storeLocator implementation
  */

angular.module('shared').factory('StoreLocatorService', ['siteConfiguration', 'siteRes',
    function (siteConfiguration, siteRes) {

        return new StoreLocator(siteConfiguration, siteRes);

    }]);;
'use strict';

/**
 * This is the helper service that wraps anchor logic
  */

angular.module('shared').factory('anchorHelper', ['$window', '$anchorScroll', function ($window, $anchorScroll) {

    var setAnchor = function (anchorName) {
        $window.location.hash = anchorName;
        $anchorScroll();
    };

    return {
        setAnchor : setAnchor
    };
}]);
;
'use strict';

/**
* This is platform cart shipping estimate implementation
*/
angular.module('cart').directive('odAppliedDynamicPromotions', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('appliedDynamicPromotionsTemplateUrl'),
        controller: 'DynamicPromotionsCtrl',
        scope: {
            appliedPromotions: '=',
            hasPromotions: '='
        }
    };
}]);;
'use strict';

angular.module('cart')
    /**
    * This controller manages the lifecycle and groups all of the various services related to the shopping cart.
    * 
    * All of the functions it exposes are on the $rootScope because they need to be accessed by other controllers
     */
    .controller('CartCtrl', ['$scope', 'CartDataStorageService',
        function ($scope, cartDataStorageService) {

            $scope.cartData = cartDataStorageService.cartData;
            $scope.loadCounter = cartDataStorageService.loadCounter;

            $scope.loadData = function () {
               
                if ($scope.preloadData !== false && $scope.preloadData !== 'false') {
                    cartDataStorageService.loadCartData();
                }
            };
        }
    ]);;
'use strict';

/**
 * this is service that stores cart data, shared across multiple cart directives
 */


angular.module('cart').factory('CartDataStorageService', ['$q', 'CartDataService', 'CartHelperService',
    function ($q, cartDataSvc, cartHelperService) {
        var cartData = {items: []};
        var loadCounter = { count: 1};
        
        var loadCartData = function () {
            var deferred = $q.defer();
            cartDataSvc.getOrderForm().$promise.then(
                function (freshCartData) {
                    sync(freshCartData, false);
                     deferred.resolve({});
                },
                function (error) { deferred.reject(error); });
            return deferred.promise;
        };

        var sync = function (freshCartData, mergeItems, restoredItems) {
            cartData.isLoaded = true;
            cartData.total = freshCartData.Total;
            cartData.subtotal = freshCartData.SubTotal;
            cartData.totalShipping = freshCartData.TotalShipping;
            cartData.totalItemsCount = freshCartData.TotalItemsCount;
            cartData.totalTax = freshCartData.TotalTax;
            cartData.TotalDiscounts = freshCartData.TotalDiscounts;
            cartData.taxes = freshCartData.Taxes;
            cartData.showShippingMarketing = freshCartData.ShowShippingMarketing;
            cartData.upsellMessage = freshCartData.UpsellMessage;
            cartData.addressInfo = freshCartData.AddressInfo;
            cartData.customer = freshCartData.Customer;
            cartData.signedIn = freshCartData.SignedIn;
            cartData.appliedPromotions = freshCartData.AppliedPromotions;
            cartData.creditMemoAmount = freshCartData.CreditMemoAmount;
            cartData.IsOrderFormOrderable = freshCartData.IsOrderFormOrderable;

            if (mergeItems !== true) {
                cartData.items = freshCartData.LineItems;
            } else {
                cartHelperService.mergeCartDataItems(cartData.items, freshCartData.LineItems, restoredItems);
            }

            loadCounter.count++;
        };

         return {
            cartData: cartData,
            loadCartData: loadCartData,
            sync: sync,
            loadCounter: loadCounter
        };

    }]);;
'use strict';

/**
 * Responsible for all cart specific communication with the server
 */
angular.module('cart').factory('CartDataService', [
    '$resource', 'appUrlBuilder',
    function($resource, appUrlBuilder) {

        var resource = $resource(appUrlBuilder.buildUrl('shoppingCartApiUrl'), null, {
            'addToCart': { method: 'PUT', url: appUrlBuilder.buildUrl('addItemToShoppingCartUrl'), isArray: false, responseType: 'json' },
            'restoreItem': { method: 'PUT', url: appUrlBuilder.buildUrl('restoreItemToShoppingCartUrl'), isArray: false, responseType: 'json' },
            'removeFromCart': { method: 'DELETE', url: appUrlBuilder.buildUrl('removeItemFromShoppingCartUrl') + '/:id', isArray: false, responseType: 'json' },
            'updateItemQuantity': { method: 'PUT', url: appUrlBuilder.buildUrl('udpateItemQuantityUrl'), isArray: false, responseType: 'json' },
            'updatePricingBonusItem': { method: 'PUT', url: appUrlBuilder.buildUrl('updatePricingBonusItemUrl'), isArray: false, responseType: 'json' },
            'updateDynPromoBonusItem': { method: 'PUT', url: appUrlBuilder.buildUrl('updateDynPromoBonusItemUrl'), isArray: false, responseType: 'json'},
            'updateItem': { method: 'POST', url: appUrlBuilder.buildUrl('updateShoppingCartItemUrl'), isArray: false, responseType: 'json' },
            'addCoupon': { method: 'PUT', url: appUrlBuilder.buildUrl('addCouponToShoppingCartUrl'), isArray: false, responseType: 'json' },
            'removeCoupon': { method: 'DELETE', url: appUrlBuilder.buildUrl('removeCouponFromShoppingCartUrl') + '/:id', isArray: false, responseType: 'json' },
            'listCoupons': { method: 'GET', url: appUrlBuilder.buildUrl('listCouponsUrl'), isArray: true, responseType: 'json' }
        });

        return {
            addItem: function(productId, itemId, quantity, autoship, personalizationData) {
                var data = { ItemId: itemId, Quantity: quantity, Options: personalizationData, ProductId: productId, Autoship: autoship };
                return resource.addToCart(data);
            },
            restoreItem: function(item) {
                var data = { ItemId: item.ItemId, Quantity: item.Quantity, Options: item.Options, ProductId: item.ProductId, Autoship: item.Autoship, BundleId: item.BundleId };
                return resource.restoreItem(data);
            },
            removeItem: function(itemId) {
                return resource.removeFromCart({ id: itemId });
            },
            getOrderForm: function() {
                return resource.get();
            },
            updateItemQuantity: function(itemGuid, quantity) {
                var data = { ItemGuid: itemGuid, Quantity: quantity };
                return resource.updateItemQuantity(data);
            },
            updatePricingBonusItem: function (itemGuid, newItemId, quantity) {
                var data = { ItemGuid: itemGuid, NewItemId: newItemId, Quantity: quantity };
                return resource.updatePricingBonusItem(data);
            },
            updateDynPromoBonusItem: function (itemGuid, newItemId, quantity) {
                var data = { ItemGuid: itemGuid, NewItemId: newItemId, Quantity: quantity };
                return resource.updateDynPromoBonusItem(data);
            },
            updateItem : function(updateItemArgs) {
                var data = { ItemGuid: updateItemArgs.ItemGuid, SelectedItemId: updateItemArgs.SelectedItemId, Options: updateItemArgs.Options };
                return resource.updateItem(data);
            },
            addCoupon: function(couponCode) {
                var data = { CouponCode: couponCode };
                return resource.addCoupon(data);
            },
            removeCoupon: function(couponCode) {
                return resource.removeCoupon({ id: couponCode });
            },

            listCoupons: function() {
                return resource.listCoupons();
            }

        };
    }
]);;

'use strict';
/**
* This service exposes methods used to manipulate the data in the cart.  
* 
* Any calls to the server should be handled by other services such as cartDataSvc.
*/
angular.module('cart').factory('CartHelperService', ['AppHelper', function (appHelper) {

    return {
        mergeCartDataItems: function (oldItems, newItems, map) {

            var bonusItems = [];

            //drop all bonus items first
            angular.forEach(oldItems, function(oldValue) {
                if (oldValue.IsBonus === true) {
                    bonusItems.push(oldItems.indexOf(oldValue));
                }
            });

            bonusItems.sort(function(a, b) {
                return b > a;
            });

            angular.forEach(bonusItems, function(i) {
                oldItems.splice(i, 1);
            });

            //now merge

            var itemToReplace;

            angular.forEach(oldItems, function(oldValue) {
                var isFound = false;
                angular.forEach(newItems, function(newValue) {
                    if (newValue.Id === oldValue.Id) {
                        isFound = true;
                        oldValue.isDeleted = false;
                        appHelper.mergeObjects(oldValue, newValue);
                    }
                });
                if (isFound === false) {

                    oldValue.isDeleted = true;
                    if (map && map.restoredItemId === oldValue.Id) {
                        itemToReplace = oldValue;
                    }
                }
            });

            var index = - 1;
            if (itemToReplace) {
                index = oldItems.indexOf(itemToReplace);
            }
            var isReplaced = false;

            angular.forEach(newItems, function(newValue) {
                var isFound = false;
                angular.forEach(oldItems, function(oldValue) {
                    if (newValue.Id === oldValue.Id) {
                        isFound = true;
                    }
                });
                if (isFound === false) {
                    if (isReplaced === false && index > -1) {
                        oldItems.splice(index, 1, newValue);
                        isReplaced = true;
                    } else {
                        oldItems.push(newValue);
                    }
                }
            });
        }
    };
}]);;
'use strict';

angular.module('cart').directive('odCartItemDetails', ['appUrlBuilder', function(appUrlBuilder) {
    return {
        restrict: 'A',
        priority: 1000,
        scope: {
            isDisabled: '=',
            hideStockInfo: '=',
            item: '=',
            onQuantityChanged: '&',
            onItemQuantityUpdateRequired: '&',
            onSelectedPricingBonusItemChanged: '&',
            onSelectedDynPromoBonusItemChanged: '&'
        },
        templateUrl: appUrlBuilder.buildTemplateUrl('cartItemDetailsTemplateUrl'),
        link: function(scope) {
            scope.quantityChanged = function(itemId) {
                scope.onQuantityChanged({ itemId: itemId });
            };
            scope.updateItemQuantity = function(itemId, quantity) {
                scope.onItemQuantityUpdateRequired({ itemId: itemId, quantity: quantity });
            };
            scope.selectedPricingBonusItemChanged = function() {
                var bonustItemGuid = scope.item.BonusItemsAddedViaPricing.Id;
                var bonustItemId = scope.item.BonusItemsAddedViaPricing.CurrentItemId;
                var quantity = scope.item.BonusItemsAddedViaPricing.Quantity;

                scope.onSelectedPricingBonusItemChanged({ itemGuid: bonustItemGuid, newItemId: bonustItemId, quantity: quantity });
            };
            scope.selectedDynamicPromoBonusItemChanged = function() {
                var itemGuid = scope.item.BonusItemsAddedViaDynamicPromotion.Id;
                var itemId = scope.item.BonusItemsAddedViaDynamicPromotion.CurrentItemId;
                var quantity = scope.item.BonusItemsAddedViaDynamicPromotion.Quantity;

                scope.onSelectedDynPromoBonusItemChanged({ itemGuid: itemGuid, newItemId: itemId, quantity: quantity });
            };
        }
    };
}]);;
'use strict';

/**
 * Lists the products that are in the cart.  Implements logic around changing of product details, such as the quantity.
 */
angular.module('cart').controller('CartItemsListingCtrl',
    ['$scope', '$window', '$location', 'CartService', 'CartDataStorageService', 'AppObserver', 'spinnerFactory', 'WishListService', 'siteConfiguration', 'appUrlBuilder', 'DialogService', 'NavigationService',
    function ($scope, $window, $location, cartService, cartDataStorageService, appObserver, spinnerFactory, wishListService, siteConfiguration, appUrlBuilder, dialogService, navigationService) {

        $scope.productData = cartDataStorageService.cartData;

        $scope.updateItemQuantity = function (itemId, quantity) {
           
            if (quantity === '' || quantity === '0') {
                $scope.removeFromCart(itemId);
            } else {
                //if any item in the cart quantity changed, will broadcast reloadShippingRates event
                var hasItemQuantityChanged = false;
                for (var i = 0; i < $scope.productData.items.length; i++) {
                    var item = $scope.productData.items[i];
                    if (item.Id === itemId && item.QuantityChanged === true) {
                        hasItemQuantityChanged = true;
                        spinnerFactory.show();

                        //for some weird reason 'jshint ignore:start - jshint ignore:end' does not work
                        cartService.updateItemQuantity(itemId, quantity).then( // jshint ignore:line
                            function() { spinnerFactory.hide(); }, // jshint ignore:line
                            function() { spinnerFactory.hide(); } // jshint ignore:line
                        ); // jshint ignore:line
                        
                    }
                }
                if (hasItemQuantityChanged) {
                    //broadcast reloadShippingRates event, current shippingEstimate controller listening on this in order to refresh the shipping rate
                    appObserver.broadcast('reloadShippingRates', {});
                }
            }
        };


        $scope.undoRemoveFromCart = function (item) {
            cartService.undoRemoveFromCart(item);

        };

        $scope.removeFromCart = function (itemId) {
            cartService.removeFromCart(itemId);
        };

        $scope.addToWishList = function (itemId) {
            wishListService.addItem(itemId, function () {

                $scope.$apply(function () {
                    var addedProductId = 0;
                    angular.forEach($scope.productData.items, function (value) {
                        if (value.ItemId == itemId) {
                            addedProductId = value.ProductId;

                        }
                    });



                    angular.forEach($scope.productData.items, function (value) {
                        if (value.ProductId == addedProductId) {
                            value.IsInWishList = true;
                        }
                    });
                });

                var baseLen = $location.protocol().length + $location.host().length + siteConfiguration.rootUrl.length + 3;
                var retUrl = $location.absUrl().substring(baseLen);

                //if we add item to wishlist via cart on the wishlist page - we have to refresh wishlist page in order to show added items
                if (retUrl.toLowerCase().indexOf(siteConfiguration.wishListUrl.toLowerCase()) === 0) {
                    navigationService.navigate($location.absUrl() + '?showCart=True');
                }

            }, function (request, status, error) {
                if (error == 'Unauthorized') {
                    navigationService.navigate(appUrlBuilder.buildUrl('signInPageUrl') + '?ReturnUrl=' + encodeURIComponent('~/ShoppingCart?addToWishList=' + itemId));
                } else {
                    dialogService.alert($window.res.GeneralError);
                }

            });
        };

        $scope.selectedPricingBonusItemChanged = function (itemGuid, newItemId, quantity) {
            cartService.updatePricingBonusItem(itemGuid, newItemId, quantity);
        };

        $scope.selectedDynPromoBonusItemChanged = function (itemGuid, newItemId, quantity) {
            cartService.updateDynPromoBonusItem(itemGuid, newItemId, quantity);
        };

        $scope.quantityChanged = function (itemId) {
            for (var i = 0; i < $scope.productData.items.length; i++) {
                var item = $scope.productData.items[i];
                if (item.Id === itemId) {
                    item.QuantityChanged = true;
                    break;
                }
            }
        };
    }
]);;
'use strict';

/**
* This is platform product listing in the cart
*/
angular.module('cart').directive('odCartItemsListing', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('cartItemsListingTemplateUrl'),
        controller: 'CartItemsListingCtrl',
        priority: 1100,
        scope: {
            isDisabled: '=',
            hideStockInfo: '='
        }
    };
}]);;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('cart').directive('odCartSummary', ['appUrlBuilder', 'AppObserver', function (appUrlBuilder, appObserver) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('cartSummaryTemplateUrl'),
        priority: 1001,
        scope: {
            cart: '=',
            //in shipping estimate page is true
            estimate: '=',
            giftCards: '='
        },
        link: function (scope, element) {
            scope.blinkGiftCardblinkItem = false;
            //change blinItem value to trigger odBlinkElement Directive when shippingRateChanged event occur
            var shippingRateChangedListener = appObserver.subscribe('shippingRateChanged', scope, function () {
                scope.blinkItem = !scope.blinkItem;
            });

            //get latest postalCode from postalCodeChanged event
            var postalCode = (typeof scope.cart === 'undefined' || scope.cart === undefined || typeof scope.cart.addressInfo === 'undefined' || scope.cart.addressInfo === undefined) ? '' : scope.cart.addressInfo.ShippingAddress.PostalCode;
            var postalCodeChangedListener = appObserver.subscribe('postalCodeChanged', scope, function (message) {
                postalCode = message.postalCode;
            });

            //decide show generic tax or detail tax 
            scope.showGenericTax = function () {
                //in shipping estimate page when change country or postal code is empty will display generic tax, 
                //in checkout page will display specific tax if shipping postal code not empty
                //reassign postalCode after scope.cart value assigned, use for checkout page to correct display generic or specific tax
                if (!scope.estimate && postalCode === '' && !(typeof scope.cart === 'undefined' || scope.cart === undefined || typeof scope.cart.addressInfo === 'undefined' || scope.cart.addressInfo === undefined)) {
                    postalCode = scope.cart.addressInfo.ShippingAddress.PostalCode;
                }
                if (postalCode === '') {
                    return true;
                } else {
                    return (scope.cart.taxes !== null && scope.cart.taxes.length === 0 || scope.cart.addressInfo.ShippingAddress.PostalCode === '');
                }
            };

           scope.cardBlink = false;
            var cardBlinkListener = appObserver.subscribe('giftCardBlinkListener', scope, function () {
                scope.cardBlink = !scope.cardBlink;
            });

            //Unbind listeners when scope is destroyed
            scope.$on('$destroy', function () {
                shippingRateChangedListener();
                postalCodeChangedListener();
                cardBlinkListener();
                element.remove();
            });
        }
    };
}]);;
'use strict';

/**
 * Responsible for all cart specific logic
 */
angular.module('cart').factory('CartService', ['$q', 'CartDataService', 'CartDataStorageService', 'ProductPersonalizationService', 'AppObserver',
    function ($q, cartDataService, cartDataStorageService, productPersonalizationService, appObserver) {

        var addToCart = function (itemData) {

            var deferred = $q.defer();

            var args = { productId: itemData.productId, itemGuid: '', hasPersonalization: itemData.hasPersonalization, enableItemSelection: itemData.enableItemSelection };

            var originalItemsCount = cartDataStorageService.cartData.totalItemsCount;

            productPersonalizationService.openPersonalizationDialog(args)
                .then(
                    function (data) {
                        var id = itemData.itemId;
                        if (data.selectedItem && data.selectedItem.Id) {
                            id = data.selectedItem.Id;
                        }
                        cartDataService.addItem(itemData.productId, id, itemData.Quantity, itemData.Autoship, data.selectedOptions)
                            .$promise.then(
                                function (value) {
                                    var itemWasAdded = originalItemsCount !== value.TotalItemsCount;
                                    cartDataStorageService.sync(value, true);
                                    deferred.resolve(itemWasAdded);
                                },
                                function (error) { deferred.reject(error); }
                            );
                    },
                    function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        var undoRemoveFromCart = function (item) {
            var deferred = $q.defer();
            cartDataService.restoreItem(item).$promise.then(
                function (value) {
                    var restoredItems = { restoredItemId: item.Id };
                    cartDataStorageService.sync(value, true, restoredItems);
                    appObserver.broadcast('reloadShippingRates', {});
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        var removeFromCart = function (itemId) {
            var deferred = $q.defer();

            cartDataService.removeItem(itemId).$promise.then(
                function (value) {
                    cartDataStorageService.sync(value, true);
                    appObserver.broadcast('reloadShippingRates', {});
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        var updatePricingBonusItem = function (itemGuid, newItemId, quantity) {
            var deferred = $q.defer();

            cartDataService.updatePricingBonusItem(itemGuid, newItemId, quantity).$promise.then(
                function (value) {
                    cartDataStorageService.sync(value, true);
                    appObserver.broadcast('reloadShippingRates', {});
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        var updateDynPromoBonusItem = function (itemGuid, newItemId, quantity) {
            var deferred = $q.defer();

            cartDataService.updateDynPromoBonusItem(itemGuid, newItemId, quantity).$promise.then(
                function (value) {
                    cartDataStorageService.sync(value, true);
                    appObserver.broadcast('reloadShippingRates', {});
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        var updateItemQuantity = function (itemId, quantity) {

            var deferred = $q.defer();

            cartDataService.updateItemQuantity(itemId, quantity).$promise.then(
                function (value) {
                    cartDataStorageService.sync(value, true);
                    appObserver.broadcast('reloadShippingRates', {});
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        var updateItem = function (updateItemArgs) {

            var deferred = $q.defer();

            cartDataService.updateItem(updateItemArgs).$promise.then(
                function (value) {
                    var restoredItems = { restoredItemId: updateItemArgs.ItemGuid };
                    cartDataStorageService.sync(value, true, restoredItems);
                    appObserver.broadcast('reloadShippingRates', {});
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        var addCoupon = function (couponCode) {
            var deferred = $q.defer();
            if (couponCode !== '') {
                cartDataService.addCoupon(couponCode).$promise.then(
                    function (value) {
                        cartDataStorageService.sync(value, false);
                        appObserver.broadcast('reloadShippingRates', {});
                        deferred.resolve({});
                    },
                    function (error) { deferred.reject(error); });
            } else {
                deferred.resolve({});
            }
            return deferred.promise;
        };
        var removeCoupon = function (couponCode) {
            var deferred = $q.defer();
            cartDataService.removeCoupon(couponCode).$promise.then(
                function (value) {
                    cartDataStorageService.sync(value, false);
                    appObserver.broadcast('reloadShippingRates', {});
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });
            return deferred.promise;
        };

        var listCoupons = function () {
            var deferred = $q.defer();
            cartDataService.listCoupons().$promise.then(
                function (value) {
                    deferred.resolve(value);
                },
                function (error) { deferred.reject(error); });
            return deferred.promise;
        };

        return {
            addToCart: addToCart,
            undoRemoveFromCart: undoRemoveFromCart,
            removeFromCart: removeFromCart,
            updateItemQuantity: updateItemQuantity,
            updatePricingBonusItem: updatePricingBonusItem,
            updateDynPromoBonusItem: updateDynPromoBonusItem,
            updateItem: updateItem,
            addCoupon: addCoupon,
            listCoupons: listCoupons,
            removeCoupon: removeCoupon,
        };
    }
]);;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('cart').directive('odCheckoutButton', ['appUrlBuilder', 'NavigationService',
    function (appUrlBuilder, navigationService) {
    return {
        restrict: 'A',
        replace: true,
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutButtonTemplateUrl'),
        controller: 'CartCtrl',
        scope: {
            showPayPal: '='
        },

        link: function (scope) {
            scope.SubmitPayPalExpress = function () {
                navigationService.navigate(appUrlBuilder.buildUrl('submitPayPalExpressUrl'));
            };

            scope.isValidForCheckout = function () {
             
                var count = 0;
                if (scope.cartData.IsOrderFormOrderable === true) {
                    for (var i = 0; i < scope.cartData.items.length; i++) {
                        if (scope.cartData.items[i].isDeleted !== true) {
                            count += 1;
                        }
                    }
                    if (count > 0) {
                        return true;
                    }
                }
                return false;
            };

            scope.signInCheckout = function () {
                if (!scope.isValidForCheckout()) {
                    return;
                }
                if (scope.cartData.signedIn) {
                    navigationService.navigate(appUrlBuilder.buildUrl('checkoutPageUrl'));
                } else {
                    navigationService.navigate(appUrlBuilder.buildUrl('signInPageUrl') + '?ReturnUrl=' + encodeURIComponent(appUrlBuilder.buildUrl('checkoutPageUrl')));
                }
            };

            scope.checkout = function () {
                if (!scope.isValidForCheckout()) {
                    return;
                }
                navigationService.navigate(appUrlBuilder.buildUrl('checkoutPageUrl'));
            };

        }
    };
}]);
;
'use strict';

angular.module('cart')
    /**
    * This controller manages display of dynamic promotions applied to shopping cart.
     */
    .controller('DynamicPromotionsCtrl', ['$scope', 
        function ($scope) { // jshint ignore:line

        }]);;
'use strict';

/**
 * Will control the lifecyle of the product personalization
 */
angular.module('cart')
    .directive('odEditCartItem', ['ProductPersonalizationService', 'CartService', function (productPersonalizationService, cartService) {
    return {
        restrict: 'A', // Only matches attribute name
        template: '<div style="width:100px;height:100px;" class="text-center image-vcenter-container"><img alt="product" ng-src="{{imageUrl}}" class="img-responsive"  ng-click="switchImage()" /></div><div ng-if="isEditable === true && disabled !== true" class="editIcon"><i class="fa fa-2x fa-pencil"></i></div>',
        scope: {
            itemGuid: '=',
            itemCategories: '=',
            productId: '=',
            itemId: '=',
            hasPersonalization: '=',
            enableItemSelection: '=',
            disabled:'=',
            imageUrl: '=',
            switchImages: '='
        },
        link: function (scope, element) {
            scope.switchImageIndex = 0;
            scope.switchImage = function () {
                if (scope.switchImages.length > 0) {
                    if (scope.switchImageIndex + 1 < scope.switchImages.length) {
                        scope.switchImageIndex++;
                    } else {
                        scope.switchImageIndex = 0;
                    }
                    scope.imageUrl = scope.switchImages[scope.switchImageIndex];
                }
            };
            //there is no personalization at all - do not show popup and return immediately
            if (scope.hasPersonalization.toString().toLowerCase() !== 'true' &&
                scope.enableItemSelection.toString().toLowerCase() !== 'true') {
                scope.isEditable = false;
            } else {
                scope.isEditable = true;
            }

            if (scope.isEditable !== false && scope.disabled !== true) {
                element.bind('click', function() {
                    var args = {
                        productId: scope.productId,
                        itemGuid: scope.itemGuid,
                        hasPersonalization: scope.hasPersonalization,
                        enableItemSelection: scope.enableItemSelection,
                        itemCategories: scope.itemCategories,
                        itemId: scope.itemId
                    };

                    productPersonalizationService.openPersonalizationDialog(args).then(function(data) {
                        var id;
                        if (data.selectedItem && data.selectedItem.Id) {
                            id = data.selectedItem.Id;
                        }
                        cartService.updateItem({ ItemGuid: scope.itemGuid, SelectedItemId: id, Options: data.selectedOptions });
                    });
                });
            }
        }
    };
}]);;
'use strict';

/**
 * Exposes the functionality that allows an end user to calculate the cost of shipping the items in the cart before purchasing it.
 */
angular.module('cart').controller('ShippingEstimateCtrl', ['$scope', 'ShippingService', 'spinnerFactory', 'AppObserver', 'CartDataStorageService',
function ($scope, shippingService, spinnerFactory, appObserver, cartDataStorageService) {
    
    $scope.cartData = cartDataStorageService.cartData;

    //broadcast postalCodeIsEmpty so the summary controller can show different taxes title (general: Taxes, specific: ON HST)
    var setPostalCode = function (value) {
        $scope.shippingPostalCode = value;
        appObserver.broadcast('postalCodeChanged', {
            postalCode: value
        });
    };
    //change shipping rate when reloadShippingRates event occur
    var cartItemListener = appObserver.subscribe('reloadShippingRates', $scope, function () {
        $scope.getShippingRates($scope.shippingRate);
    });

    $scope.initLoad = true;
    setPostalCode($scope.cartData.addressInfo ? $scope.cartData.addressInfo.BillingAddress.PostalCode : '');
    // use to control display postal code error message
    $scope.shippingPostalCodeValid = true;


    $scope.getShippingRates = function (shippingRateId) {
        shippingService.getShippingRates($scope.shippingCountry, '', $scope.shippingPostalCode, true).$promise.then(function (value) {
            $scope.shippingRates = value.shippingRates;
            // set first rate as default & update cart shipping amount
            if (shippingRateId && shippingService.ratesContain($scope.shippingRates, shippingRateId)) {
                $scope.shippingRate = shippingRateId;
            } else {
                $scope.shippingRate = $scope.shippingRates[0].Id;
            }
            $scope.updateShippingRate();
        });
    };

    $scope.shippingCountryChange = function () {
        setPostalCode('');
        $scope.shippingPostalCodeValid = true;
        $scope.getShippingRates($scope.shippingRate);
    };

    $scope.getShippingCountries = function() {
        shippingService.getShippingCountries().$promise.then(function(value) {
            $scope.shippingCountries = value.shippingCountries;
            // set first country as default if customer not sign in & reload shipping rate by calling getShippingRates();
            var countryId = $scope.cartData.addressInfo ? $scope.cartData.addressInfo.BillingAddress.Country.CountryId : $scope.shippingCountries[0].Id;
            if (shippingService.countryContain($scope.shippingCountries, countryId)) {
                $scope.shippingCountry = countryId;
            } else {
                $scope.shippingCountry = $scope.shippingCountries[0].Id;
            }
            $scope.getShippingRates($scope.shippingRate);
        });
    };

    $scope.updateShippingAddress = function () {
        setPostalCode($scope.shippingPostalCode);
        shippingService.updateShippingAddress($scope.shippingCountry, $scope.shippingPostalCode, true, '','','','','').$promise.then(function (value) {
            if (value.Success) {
                $scope.getShippingRates($scope.shippingRate);
                $scope.shippingPostalCodeValid = true;

            } else {
                $scope.shippingPostalCodeValid = false;
                // this error message might need show up in the front
                console.log(value.Message);
            }
        }, function() {
            console.log('updateShippingAddress error occur');
        });
    };

    $scope.updateShippingRate = function () {
        //update cart shipper id & reload cart data after rate change
        shippingService.updateShippingRate($scope.shippingRate).$promise.then(
            function (value) {
                //we have to merge cart items, because some of them might be reloaded
                cartDataStorageService.sync(value, true);
                spinnerFactory.hide();
                //don't broadcast shipping rate change when cart initial load
                if ($scope.initLoad) {
                    $scope.initLoad = false;
                } else {
                    //broadcast shippingRateChanged event, then summary controller can do something on shipping rate (fade in default: could change the behavior by modify fade-in class in common.less)
                    appObserver.broadcast('shippingRateChanged', {});
                }
            },
            function () {
                spinnerFactory.hide();
            }
        );
    };
    
    //first time page initial load countries
    $scope.getShippingCountries();

    //Unbind listeners when scope is destroyed
    $scope.$on('$destroy', function () {
        cartItemListener();
    });
}]);;
'use strict';

/**
* This is platform cart shipping estimate implementation
*/
angular.module('cart').directive('odShippingEstimate', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('shippingEstimateTemplateUrl'),
        controller: 'ShippingEstimateCtrl',
        scope: {
        }
    };
}]);;
'use strict';

/**
 * Provides all of the methods that communicate with the server for shipping estimate functionality
 */
angular.module('cart').factory('ShippingService', [
        '$resource', 'appUrlBuilder',
    function ($resource, appUrlBuilder) {
            var resource = $resource(appUrlBuilder.buildUrl('orderFormApiUrl'), null, {
                'getShippingCountries': { method: 'GET', url: appUrlBuilder.buildUrl('getShippingCountriesUrl'), isArray: false },
                'getShippingRates': { method: 'GET', url: appUrlBuilder.buildUrl('getShippingRatesUrl'), isArray: false, responseType: 'json' },
                'updateShippingAddress': { method: 'PUT', url: appUrlBuilder.buildUrl('updateShippingAddressUrl'), isArray: false, responseType: 'json' },
                'updateShippingRate': { method: 'PUT', url: appUrlBuilder.buildUrl('updateShippingRateUrl'), isArray: false, responseType: 'json' }
            });

            return {
                getShippingCountries: function () {
                    return resource.getShippingCountries();
                },
                getShippingRates: function (countryId, province, destinationPostalCode, bypassRateLookup) {
                    return resource.getShippingRates({ countryId: countryId, province: province, destinationPostalCode: destinationPostalCode, bypassRateLookup: bypassRateLookup });
                },
                updateShippingAddress: function (countryId, destinationPostalCode, postalCodeCountryOnly, province, city, address1, address2, address3, firstName, lastName) {
                    var data = { countryId: countryId, destinationPostalCode: destinationPostalCode, postalCodeCountryOnly: postalCodeCountryOnly, province: province, city: city, address1: address1, address2: address2, address3: address3, firstName: firstName, lastName: lastName };                   
                    return resource.updateShippingAddress(data);
                },
                updateShippingRate: function (shipperId) {
                    var data = { shipperId: shipperId };
                    return resource.updateShippingRate(data);
                },
                //check countryId exists in countries
                countryContain: function (countries, countryId) {
                    if (!countryId || countryId === -1 || countries.length < 1) {
                        return false;
                    }
                    var isFound = false;
                    angular.forEach(countries, function (country) {
                        if (country.Id === countryId) {
                            isFound = true;
                        }
                    });
                    return isFound;
                },
                //check countryId exists in rates
                ratesContain: function (rates, rateId) {
                    if (!rateId || rateId === -1 || rates.length < 1) {
                        return false;
                    }
                    var isFound = false;
                    angular.forEach(rates, function (rate) {
                        if (rate.Id === rateId) {
                            isFound = true;
                        }
                    });
                    return isFound;
                }
            };
    }
]);

;
'use strict';

/**
* This is platform implemented shopping cart.
* This directive is watching for shopping cart changes and updates all external elements, that are not part of the shoppingCart module, so that
* external elements reflect changes in the cart.  Update are done via handlers.  If you want to extend this, you should write your custom handlers
* handlers that accept scope.cartData as a parameter
*/
angular.module('cart').directive('odShoppingCart', ['$window', 'appUrlBuilder', function ($window, appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('shoppingCartTemplateUrl'),
        scope: {
            onCartChanged: '@',
            preloadData: '@'
        },
        controller: 'CartCtrl',
        link: function (scope, element) {

            // We could watch for  scope.cartData.totalItemsCount and  scope.$root.$watchCollection for  scope.cartData.items
            // but it is pretty expensive, so we will watch for the load counter instead, to make it lightweight

            var watcher = scope.$watch('loadCounter.count', function () {

                if (scope.onCartChanged && typeof ($window[scope.onCartChanged]) !== 'undefined') {
                    $window[scope.onCartChanged](scope.cartData);
                }

            });


            element.on('$destroy', function () {
                // Dispose watcher
                watcher();
            });

            scope.loadData();
        }
    };
}]);;
'use strict';

/**
 * Controller that allows to open shopping cart in a modal window. 
 */
angular.module('cart').controller('ShoppingCartModalCtrl', ['$scope', '$q', '$modal', '$window', 'appUrlBuilder', 'CartDataStorageService', 'CartService',
    function ($scope, $q, $modal, $window, appUrlBuilder, cartDataStorageService, cartService) {

        $scope.loadCounter = cartDataStorageService.loadCounter;
        $scope.cartData = cartDataStorageService.cartData;

        $scope.preloadData = function() {
            cartDataStorageService.loadCartData();
        };

        $scope.$root.showCart = function () {
            $modal.open({
                templateUrl: appUrlBuilder.buildTemplateUrl('shoppingCartModalTemplateUrl'),
                backdrop: 'static',
                controller: 'ShoppingCartModalInstanceCtrl',
                windowClass: 'modal-vertical-centered',
                size: 'lg'
            });
        };

        $scope.$root.isCartEmpty = function () {
            return $scope.cartData.items.length < 1;
        };

        $scope.$root.addToCart = function (itemData) {

            var deferred = $q.defer();

            cartService.addToCart(itemData).then(function (value) {
                if (value) {
                    deferred.resolve({});
                } else {
                    deferred.reject('nothing was added');
                }
            }, function (error) { deferred.reject(error); });

            return deferred.promise;
        };

        //Pop up cart if query string contains 'showCart=True'
        if ($window.location.search.indexOf('showCart=True') > 0) {
            $scope.$root.showCart();
        }
       
    }]);;
'use strict';

/**
 * Directive that allows to open shopping cart in a modal window. 
 */
angular.module('cart').directive('odShoppingCartModal', [ '$window', 
    function ($window) {
        return {
            restrict: 'A',
            controller: 'ShoppingCartModalCtrl',
            scope: {
                onCartChanged: '@'
            },
            link: function(scope, element) {

                // We could watch for  scope.cartData.totalItemsCount and  scope.$root.$watchCollection for  scope.cartData.items
                // but it is pretty expensive, so we will watch for the load counter instead, to make it lightweight

                var watcher = scope.$watch('loadCounter.count', function() {

                    if (scope.onCartChanged && typeof ($window[scope.onCartChanged]) !== 'undefined') {
                        $window[scope.onCartChanged](scope.cartData);
                    }

                });

                element.on('$destroy', function() {
                    // Dispose watcher
                    watcher();
                });

                scope.preloadData();
            }
        };
    }
]);;
'use strict';

/**
 * Instance of a shopping cart modal window. 
 */
angular.module('cart').controller('ShoppingCartModalInstanceCtrl', ['$scope', '$modalInstance',
    function ($scope, $modalInstance) {

        $scope.close = function() {
            $modalInstance.close();
        };
    }]);;
'use strict';

angular.module('address')
    .controller('addressAutocompleteCtrl', ['$scope',
        function ($scope) {
            $scope.onAutocompleteAddressSelected =function($item, $model) {
                $scope.fullForm = {
                    address1: $model._address1,
                    address2: $model._address2,
                    address3: $model._address3,
                    city: $model._city,
                    province: $model._state,
                    postalCode: $model._zipCode,
                    country: {
                        countryCode: $model._country._countryCode,
                        countryId: $model._country._id,
                        countryName: $model._country._name,
                    },
                };
                $scope.lockFullForm();
            };
        }]);;
angular.module('address').directive('odAddressAutocompleteDirective', ['AddressSvc', 'appUrlBuilder',
    function(addressSvc, appUrlBuilder) {
        return {
            restrict: 'A',
            templateUrl: appUrlBuilder.buildTemplateUrl('addressAutocompleteTemplateUrl'),
            controller: 'addressAutocompleteCtrl',
            link: function(scope) {
                scope.autocomplete = function(address) {
                    return addressSvc.autocompleteAddress(scope, address).$promise.then(function(response) {
                        return response;
                    });
                };

            },
        };
    }]);;
'use strict';
/**
 * Responsible for most behavior within the Address Module such as:
 *  - Displaying the Country list and calling the sub-form directive
 *  - Returning data from sub-form
 */
angular.module('address')
    .directive('odAddressForm', ['appUrlBuilder', 'AddressSvc',
        function (appUrlBuilder, addressSvc) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('countryListTemplateUrl'),
        scope: {
            addressData: '=',
            onDone: '&',
            onEdit: '&',
            doneButtonLabelKey: '@',
            triggerDoneButtonEvent: '='
        },
        
        link: function (scope) {

            scope.selectedCountry = {};

            addressSvc.getCountryInfos().$promise.then(
                function(data) {
                    scope.countryInfos = data.countryInfos;
                    scope.setSelectedCountry();
                }
            );

            scope.done = function(data) {
                scope.onDone({ data: data });
            };

            scope.edit = function() {
                scope.onEdit();
            };

            scope.$watch('addressData', function () {
                if (scope.addressData) {
                    scope.setSelectedCountry();
                }
            });

            scope.setSelectedCountry = function () {
                if (scope.addressData) {
                    if (scope.countryInfos && scope.addressData.country) {
               
                        angular.forEach(scope.countryInfos, function(countryInfo) {
                            if (scope.addressData.country.countryCode == countryInfo.countryCode) {
                                scope.selectedCountry = countryInfo;
                            }
                            if (scope.addressData.country.countryId == countryInfo.countryId) {
                                scope.selectedCountry = countryInfo;
                            }
                        });
                    }
                }
            };

        }
    };
    }]);

;
'use strict';
/**
 * Responsible for Validation Modal behaviour within the Address Module such as:
 *  
 */
angular.module('address')
    .controller('addressLookupCtrl', [
        '$scope', '$modalInstance', 'addressList',
        function($scope, $modalInstance, addressList) {
            $scope.addressList = addressList;
            $scope.lookupModal = {
                selectedAddress: $scope.addressList[0]
        };

    $scope.acceptLookupAddress = function () {
        $scope.selectedAddress = {
            address1: $scope.lookupModal.selectedAddress._address1,
            address2: $scope.lookupModal.selectedAddress._address2,
            address3: $scope.lookupModal.selectedAddress._address3,
            city: $scope.lookupModal.selectedAddress._city,
            province: $scope.lookupModal.selectedAddress._state,
            postalCode: $scope.lookupModal.selectedAddress._zipCode,
            country: {
                countryCode: $scope.lookupModal.selectedAddress._country._countryCode,
                countryId: $scope.lookupModal.selectedAddress._country._id,
                countryName: $scope.lookupModal.selectedAddress._country._name
            }
        };
        $scope.ok();
    };

    $scope.ok = function () {
        $modalInstance.close($scope.selectedAddress);
    };

    $scope.cancel = function () {
        $modalInstance.dismiss('cancel');
    };
 
}]);;
'use strict';
/**
 * Responsible for most behavior within the Address Module such as:
 *  - Watching the country selection and calling the proper address form
 *  - Calling form type behavior (validate, lookup, auto-complete)
 *  - Returning proper data back
 */
angular.module('address')
    .directive('odAddressSubform', ['$compile', '$http', '$modal', 'AddressSvc', 'appUrlBuilder', 'DialogService', 'siteRes',
        function ($compile, $http, $modal, addressSvc, appUrlBuilder, dialogService, siteRes) {
            return {
                restrict: 'A',
                templateUrl: appUrlBuilder.buildTemplateUrl('addressFormTemplateUrl'),
                scope: {
                    addressData: '=',
                    selectedCountry: '=',
                    onDone: '&',
                    onEdit: '&',
                    doneButtonLabelKey: '@',
                    triggerDoneButtonEvent: '='
                },
                link: function (scope, element) {
                    var rootUrl = appUrlBuilder.buildUrl('addressFormTemplateUrl');
                    var childScope;
                    var addressData = scope.addressData;
                    
                    scope.$watch('selectedCountry', function (selectedCountry) {
                        //disable "Create Account" button
                        scope.onEdit();

                        var url = rootUrl;
                        if (selectedCountry.countryCode) {
                            url += '?Country=' + selectedCountry.countryCode + '&DoneButtonLabelKey=' + scope.doneButtonLabelKey;
                            addressData = scope.addressData;
                        }
                    
                        $http.get(url, {
                        }).success(
                            function (html) {
                                if (childScope) {
                                    childScope.$destroy();
                                }
                                element.html(html);
                              
                                childScope = scope.$new();

                                childScope.showValidateButton = false;
                                childScope.enableValidateButton = true;
                                childScope.showDoneButton = false;
                                childScope.enableDoneButton = true;
                                childScope.showEditButton = false;
                                childScope.lockFields = false;

                                childScope.addressData = addressData;
                                childScope.selectedCountry = selectedCountry;
                                childScope.triggerDoneButtonEvent = scope.triggerDoneButtonEvent? scope.triggerDoneButtonEvent: false;
                                childScope.provinces = {};

                                if (childScope.addressData && (childScope.selectedCountry && childScope.addressData.country.countryCode === childScope.selectedCountry.countryCode)) {
                                        childScope.fullForm = angular.copy(childScope.addressData);
                                        childScope.fullForm.country = childScope.selectedCountry;
                                } else {
                                    if (childScope.selectedCountry) {
                                            childScope.fullForm = { country: childScope.selectedCountry };
                                    }
                                }

                                if (childScope.selectedCountry.countryCode ) {
                                    //If mode is not "no lookup"
                                    childScope.showValidateButton = true;
                                    //Other buttons such as lookup
                                    childScope.showLookupButton = true;
                                    childScope.enableLookupButton = true;

                                    //in the future maybe dynamically call the following web api based on the field in the json file
                                    //have not finalized it yet and will revisit it
                                    addressSvc.getCountryProvinces(selectedCountry.countryCode).$promise.then(
                                        function(data) {
                                            childScope.provinces = data.provinces;
                                        }
                                    );
                                }


                                childScope.validateForm = function () {

                                    childScope.enableValidateButton = false;

                                    addressSvc.validateAddress(childScope).$promise.then(
                                        function (value) {

                                            childScope.gasResponse = angular.copy(value);
                                            if (childScope.gasResponse.length > 0) {
                                                var modalInstance = $modal.open({
                                                    templateUrl: appUrlBuilder.buildTemplateUrl('addressValidateModalUrl'),
                                                    controller: 'addressValidateCtrl',
                                                    backdrop: 'static',
                                                    resolve: {
                                                        addressList: function () {
                                                            return childScope.gasResponse;
                                                        },
                                                        enteredAddress: function () {
                                                            return childScope.fullForm;
                                                        }
                                                    }
                                                });

                                                modalInstance.result.then(function (selectedAddress) {
                                                    childScope.fullForm = selectedAddress;
                                                    childScope.lockFullForm();
                                                    childScope.enableValidateButton = true;
                                                    childScope.triggerDoneButtonEventIfNeeded(childScope.triggerDoneButtonEvent);
                                                }, function () {
                                                    //Canceled or Closed
                                                    childScope.enableValidateButton = true;
                                                });
                                            }
                                            else {
                                                dialogService.alert(siteRes.ValAdd_NoMatch);
                                                console.log('Validate Address: No match returned.');
                                                childScope.enableValidateButton = true;
                                            }

                                        }, function () {
                                            dialogService.alert(siteRes.ValAdd_Error);
                                            console.log('Validate Address: error occured.');
                                            childScope.enableValidateButton = true;
                                            childScope.showDoneButton = true;
                                        }

                                        
                                    );

                                  
                                };

                                childScope.triggerDoneButtonEventIfNeeded = function (triggerDoneButtonEvent) {
                                           if (triggerDoneButtonEvent) {
                                               childScope.done();
                                           }
                                };

                                childScope.lookupForm = function () {

                                    childScope.enableLookupButton = false;

                                    addressSvc.lookupAddress(childScope).$promise.then(
                                        function(value) {
                                            childScope.gasResponse = angular.copy(value);
                                            if (childScope.gasResponse.length > 0) {
                                                var modalInstance = $modal.open({
                                                    templateUrl: appUrlBuilder.buildTemplateUrl('addressLookupModalUrl'),
                                                    controller: 'addressLookupCtrl',
                                                    backdrop: 'static',
                                                    resolve: {
                                                        addressList: function() {
                                                            return childScope.gasResponse;
                                                        },
                                                        enteredAddress: function() {
                                                            return childScope.fullForm;
                                                        }
                                                    }
                                                });

                                                modalInstance.result.then(function(selectedAddress) {
                                                    childScope.fullForm = selectedAddress;
                                                    childScope.lockFullForm();
                                                    childScope.enableLookupButton = true;
                                                    childScope.triggerDoneButtonEventIfNeeded(childScope.triggerDoneButtonEvent);
                                                }, function() {
                                                    //Canceled or Closed
                                                    childScope.enableLookupButton = true;
                                                });
                                            } else {
                                                dialogService.alert(siteRes.ValAdd_NoMatch);
                                                console.log('Lookup Address: No match returned.');
                                                childScope.enableLookupButton = true;
                                            }
                                        }, function() {
                                            dialogService.alert(siteRes.LookupAdd_Error);
                                            console.log('Lookup Address: error occured.');
                                            childScope.enableLookupButton = true;
                                            childScope.showDoneButton = true;
                                        }
                                    );
                                };
                                //Other functions such as lookup and autocomplete.

                                childScope.done = function () {
                                    scope.enableDoneButton = false;
                                    scope.addressData = angular.copy(childScope.fullForm);
                                    if (childScope.selectedCountry) {
                                        scope.addressData.country = angular.copy(childScope.selectedCountry);
                                    }
                                    scope.onDone({ data: scope.addressData });
                                    scope.enableDoneButton = true;
                                };
                                childScope.lockFullForm = function () {
                                    childScope.lockFields = true;
                                    childScope.showEditButton = true;
                                    childScope.showValidateButton = false;
                                    childScope.showDoneButton = true;
                                };
                                childScope.editForm = function () {
                                    if (childScope.lockFields === true) {
                                        childScope.showValidateButton = true;
                                        childScope.lockFields = false;
                                        childScope.showEditButton = false;
                                        childScope.showDoneButton = false;
                                        scope.onEdit();
                                    }
                                };
                                
                                $compile(element.contents())(childScope);
                            }
                        );
                    });
                }
            };
        }]);;
'use strict';

/**
 * Responsible for all Address Form Module specific communication with the server:
 *  - Getting list of countries From the AddressForm WebAPI
 *  - Validating address with GAS
 */
angular.module('address').factory('AddressSvc', ['$resource', 'appUrlBuilder',
    function ($resource, appUrlBuilder) {

        //from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
        var generateGuid = (function () {
            function s4() {
                return Math.floor((1 + Math.random()) * 0x10000)
                           .toString(16)
                           .substring(1);
            }
            return function () {
                return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
                       s4() + '-' + s4() + s4() + s4();
            };
        })();

        var UUID = generateGuid();

        var gasResource = $resource(appUrlBuilder.buildUrl('globalAddressServiceApiUrl'), null, {
            'validateAddress' : {
                method: 'POST',
                url: appUrlBuilder.buildUrl('validateAddressUrl'),
                isArray: true,
                responseType: 'json'
            },
            'lookupAddress' : {
                method: 'POST',
                url: appUrlBuilder.buildUrl('lookupAddressUrl'),
                isArray: true,
                responseType: 'json'
            }
        });

        var addressFormResource = $resource(appUrlBuilder.buildUrl('addressFormServiceApiUrl'), null, {
            'getCountryInfos': {
                method: 'GET',
                url: appUrlBuilder.buildUrl('getCountryInfosApiUrl'),
                isArray: false,
                responseType: 'json',
                cache: true
            },

            'getDefaultCountry': {
                method: 'GET',
                url: appUrlBuilder.buildUrl('getDefaultCountryApiUrl'),
                isArray: false,
                responseType: 'json'
            },

            'getCountryProvinces': {
                method: 'GET',
                url: appUrlBuilder.buildUrl('getCountryProvincesUrl'),
                isArray: false,
                responseType: 'json'
            }
        });

        return {
            validateAddress: function ($scope) {
                var addressData = {
                    Country: $scope.fullForm.country.countryCode,
                    ContactName: '',
                    Organization : '',
                    Department : '',
                    Building : '',
                    SubBuilding1 : '',
                    SubBuilding2 : '',
                    StreetNumber : '' ,
                    Street : $scope.fullForm.address1,
                    DeliveryService1 : '',
                    DeliveryService2 : '',
                    Locality1: $scope.fullForm.city,
                    Locality2 : '',
                    Locality3 : '',
                    Province: $scope.fullForm.province,
                    PostalCode: $scope.fullForm.postalCode,
                    SessionId: UUID
                };
                return gasResource.validateAddress(addressData);
            },

            getCountryInfos: function () {
                return addressFormResource.getCountryInfos();
            },

            getCountryProvinces: function (countryCode) {
                return addressFormResource.getCountryProvinces({ countryCode: countryCode });
            },
            lookupAddress: function($scope) {
                var addressData = {
                    Country: $scope.fullForm.country.countryCode,
                    Street: $scope.lookupForm.address1,
                    StreetNumber: $scope.lookupForm.streetNumber,
                    PostalCode: $scope.lookupForm.postalCode,
                    SessionId: UUID
                };
                return gasResource.lookupAddress(addressData);
            },
            autocompleteAddress: function($scope, address) {
                var addressParts = address.split(',');
                var street = '';
                var city = '';
                var province = '';
                if (addressParts.length > 0) {
                    street = addressParts[0];
                }
                if (addressParts.length > 1) {
                    city = addressParts[1];
                }
                if (addressParts.length > 2) {
                    province = addressParts[2];
                }

                var addressData = {
                    Country: $scope.fullForm.country.countryCode,
                    Street: street,
                    Locality1: city,
                    Province: province,
                    SessionId: UUID
                };
                return gasResource.lookupAddress(addressData);
            }
        };
    }
]);;
'use strict';
/**
 * Responsible for Validation Modal behaviour within the Address Module such as:
 *  
 */
angular.module('address')
   .controller('addressValidateCtrl', ['$scope', '$modalInstance', 'addressList', 'enteredAddress',
function ($scope, $modalInstance, addressList, enteredAddress) {
    $scope.addressList = addressList;
    $scope.enteredAddress = enteredAddress;
    $scope.validateModalIndex = 0;
    $scope.validateModalButton = { isPrevEnabled: false, isNextEnabled: false };

    $scope.toggleNextPrev = function() {
        $scope.validateModalButton.isPrevEnabled = $scope.validateModalIndex > 0;
        $scope.validateModalButton.isNextEnabled = $scope.validateModalIndex < $scope.addressList.length - 1;
    };

    $scope.fillValidateModal = function () {
        $scope.validateModal = angular.copy($scope.addressList[$scope.validateModalIndex]);
        $scope.toggleNextPrev();
    };

    $scope.getNextValidateAddress = function() {
        if (($scope.validateModalIndex + 1) < $scope.addressList.length) {
            ++$scope.validateModalIndex;
            $scope.fillValidateModal();
        }
        $scope.toggleNextPrev();
    };

    $scope.getPrevValidateAddress = function() {
        if (($scope.validateModalIndex - 1) > -1) {
            --$scope.validateModalIndex;
            $scope.fillValidateModal();
        }
        $scope.toggleNextPrev();
    };

    $scope.acceptValidateAddress = function () {
        $scope.selectedAddress = {
            address1: $scope.validateModal._address1,
            address2: $scope.validateModal._address2,
            address3: $scope.validateModal._address3,
            city: $scope.validateModal._city,
            province: $scope.validateModal._state,
            postalCode: $scope.validateModal._zipCode,
            country: {
                countryCode: $scope.validateModal._country._countryCode,
                countryId: $scope.validateModal._country._id,
                countryName: $scope.validateModal._country._name
            }
        };
        $scope.ok();
    };

    $scope.keepEnteredAddress = function () {
        $scope.selectedAddress = angular.copy($scope.enteredAddress);
        $scope.ok();
    };

    $scope.ok = function() {
        $modalInstance.close($scope.selectedAddress);
    };

    $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
    };

    $scope.showField = function(data)
    {
        if (data) {
            if (data.length > 0) {
                return true;
            } else { return false; }
        } else { return false; }
    };

    $scope.fillValidateModal();

 }]);;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('checkout').directive('odCheckoutContact', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        replace: true,
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutContactTemplateUrl')
    };
}]);
;
'use strict';

/**
* This directive is loading cart data and displaying giftcards on the page.
*/
angular.module('checkout').directive('odCheckoutCreateAccount', ['appUrlBuilder',
    function (appUrlBuilder) {
        return {
            restrict: 'A',
            replace: true,
            templateUrl: appUrlBuilder.buildTemplateUrl('checkoutCreateAccountTemplateUrl'),
            link: function(scope) {
                scope.passwordType = 'password';
            }
        };
    }]);;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('checkout').directive('odCheckoutCreditCard', ['$q', 'CheckoutSvc', 'appUrlBuilder', function ($q, checkoutSvc, appUrlBuilder) {
    return {
        restrict: 'A',
        replace: true,
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutCreditCardTemplateUrl'),
        controller: 'CreditCardCtrl',
        scope: {
            addressData: '=',
            billingSame: '=',
        },
        link: function(scope) {
            scope.useShippingAddress = true;
        }
    };
}]);;
'use strict';

/**
 * this is the service to validate credit card data
 */


angular.module('checkout').factory('CheckoutCreditCardValidationService', ['CheckoutSvc',
    function (checkoutSvc) {
        
        var validateCardType = function (checkoutState) {
            return checkoutState.creditCardType !== null && validateCardNumber(checkoutState, true);
        };

        var validateCardNumber = function (checkoutState, allowEmpty) {
            if (checkoutState.creditCardData.cardNumber === undefined) {
                checkoutState.creditCardData.cardNumber = '';
            }

            if (checkoutSvc.hpciEnabled() === true || (allowEmpty && checkoutState.creditCardData.cardNumber === '')) {
                return true;
            }

            if (!(typeof checkoutState.creditCardType === 'undefined' || checkoutState.creditCardType === undefined) &&
                checkoutState.creditCardType !== null &&
                !(typeof checkoutState.creditCardType._binRegex === 'undefined' || checkoutState.creditCardType._binRegex === undefined) &&
                checkoutState.creditCardType._binRegex !== null &&
                checkoutState.creditCardType._binRegex.length > 0) {
                var match = checkoutState.creditCardData.cardNumber.match(checkoutState.creditCardType._binRegex);
                return match === null ? false : true;
            } else {
                return true;
            }
        };

        var validateMonth = function (checkoutState) {
            return (checkoutState.creditCardData.expireMonth > 0);
        };

        var validateYear = function (checkoutState) {
            return (checkoutState.creditCardData.expireYear > 0);
        };

        var validateCardValidation = function (checkoutState) {
            //we should process hpci first
            if (checkoutSvc.hpciEnabled() && !checkoutState.hpciProcessed) {
                return true;
			} else {
				if (checkoutState.requireCSCValidation) {
					if (checkoutState.creditCardData.cardValidation === undefined) {
						return false;
					} else {
						return (checkoutState.creditCardData.cardValidation.length > 2);
					}
				} else {
					return true;
				}
                
            }
        };

        var validateName = function (checkoutState) {
            if (checkoutState.creditCardData.name === undefined) {
                return false;
            } else {
                return (checkoutState.creditCardData.name.length > 0);
            }
        };

        var isCardValid = function (checkoutState) {
            var result = validateCardType(checkoutState) &&
                validateCardNumber(checkoutState, false) &&
                validateMonth(checkoutState) &&
                validateYear(checkoutState) &&
                validateCardValidation(checkoutState) &&
                validateName(checkoutState);

            return result;
        };

        return {
            validateCardType: validateCardType,
            validateCardNumber: validateCardNumber,
            validateMonth: validateMonth,
            validateYear: validateYear,
            validateCardValidation: validateCardValidation,
            validateName: validateName,
            isCardValid: isCardValid
        };
    }]);;
'use strict';
/**
 * Responsible for all checkout specific logic
 */
angular.module('checkout').controller('CheckoutCtrl', ['$scope', '$window', 'CheckoutSvc', 'CartDataStorageService', 'ShippingService', 'AppObserver', 'AddressDataHelper', 'siteConfiguration', 'siteRes', 'CheckoutDataStorageService', 'CheckoutSubmitCartSvc', 'CheckoutHelperService', 'anchorHelper',
    function ($scope, $window, checkoutSvc, cartDataStorageService, shippingService, appObserver, addressDataHelper, siteConfiguration, siteRes, checkoutDataStorageService, checkoutSubmitCartSvc, checkoutHelperService, anchorHelper) {

        $scope.cartData = cartDataStorageService.cartData;
        $scope.checkoutState = checkoutDataStorageService.checkoutState;
      
        $scope.identityName = 'CheckoutCtrl';

        $scope.password = '';

   //for paypal
        $scope.firstName = '';
        $scope.lastName = '';
        $scope.updateShippingAddressSuccess = true;

        var shippingAddressIsEmpty = true;

        $scope.emailRegex = siteConfiguration.emailRegex;

        $scope.preloadData = function() {
            //preload cart data
            cartDataStorageService.loadCartData().then(function () {          
                //stage = 3 means come from PayPal express
                $scope.PayPalExpress = checkoutSvc.parseQueryString($window.location.search, 'stage') === '3';
                var lastOrderInfo = $scope.cartData.addressInfo.LastOrderInfo;
                var currentOrderInfo = $scope.cartData.addressInfo.CurrentOrderInfo;
                if (!$scope.cartData.signedIn) {
                    $scope.clearAddress($scope.cartData.addressInfo.ShippingAddress);
                    $scope.clearAddress($scope.cartData.addressInfo.BillingAddress);
                }
                var sAddress = $scope.cartData.signedIn && !$scope.PayPalExpress ? lastOrderInfo.ShippingAddress : $scope.cartData.addressInfo.ShippingAddress;
                shippingAddressIsEmpty = sAddress.Address1 === '' && sAddress.City === '' && sAddress.Province === '';
                if ($scope.cartData.signedIn && shippingAddressIsEmpty) {
                    sAddress = $scope.cartData.addressInfo.BillingAddress;
                }
                var bAddress = $scope.cartData.addressInfo.BillingAddress;
                var shippingAddress = checkoutHelperService.addressDataMap(sAddress);
                var billingAddress = checkoutHelperService.addressDataMap(bAddress);
                $scope.addressData = { shippingData: shippingAddress, billingData: billingAddress };

                //for guest user: only show address section, hide all other sections
                //for registered user: user's last shipping address, payment method and shipping method use to pre-populate the existing form
                $scope.shippingRate = currentOrderInfo.ShipperId;
                if ($scope.cartData.signedIn) {
                    $scope.updateShippingAddress(shippingAddress, true);
                    $scope.cartData.phone = shippingAddressIsEmpty ? $scope.cartData.customer.Phone : lastOrderInfo.Phone;
                    $scope.cartData.email = shippingAddressIsEmpty ? $scope.cartData.customer.Email : lastOrderInfo.Email;
                    // Note: ReceiverName is deprecated since we have it in the AddressInfo of the shipping object
                    $scope.cartData.receiverName = '';
                    $scope.cartData.isGift = currentOrderInfo.IsGift;
                    $scope.cartData.giftNote = currentOrderInfo.GiftNote;
                    $scope.checkoutState.paymentType = $scope.PayPalExpress ? 2 : lastOrderInfo.PaymentType;
                    $scope.checkoutState.addressSec = false;
                    $scope.checkoutState.receiverSec = false;
                    $scope.checkoutState.deliverToSec = true;
                    $scope.checkoutState.shippingMethodSec = false;
                    $scope.checkoutState.shipUsingSec = true;
                    $scope.checkoutState.contactSec = true;
                    $scope.checkoutState.currentStage = 3;
                } else {
                    $scope.checkoutState.addressSec = true;
                }
                $scope.paymentMethods.showCreditCardChecked = $scope.checkoutState.paymentType === 1;
            });
        };

        $scope.clearAddress = function (address) {
            address.Nickname = '';
            address.FirstName = '';
            address.LastName = '';
            address.Address1 = '';
            address.Address2 = '';
            address.Address3 = '';
            address.City = '';
            address.Province = '';
            address.PostalCode = '';
            if (address.Country !== null) {
                address.Country.CountryCode = '';
                address.Country.CountryName = '';
                address.Country.CountryId = -1;
            }
        };

        $scope.updateShippingAddress = function (data, isInit) {          
            $scope.addressData.shippingData = data;
            addressDataHelper.updateShippingData(data);

            $scope.getShippingRates(data);

            addressDataHelper.updateBillingData(data);
            shippingService.updateShippingAddress(data.country.countryId, data.postalCode, false, data.province, data.city, data.address1, data.address2, data.address3,data.FirstName,data.LastName).$promise.then(
                function(value) {
                    cartDataStorageService.loadCartData();
                    anchorHelper.setAnchor('shippingAnchor');
                    $scope.updateShippingAddressSuccess = true;
                    if (!value.Success) {
                        console.log(value.Message);
                    }
                    $scope.checkoutState.addressSec = false;
                    $scope.checkoutState.receiverSec = isInit ? !$scope.cartData.signedIn : true;
                }, function() {
                    $scope.updateShippingAddressSuccess = false;
                    console.log('updateShippingAddress error occur');
                });
        };

        $scope.editBillingInfo = function () {
            $scope.checkoutState.billingSec = false;
            $scope.checkoutState.paymentSec = true;
            $scope.checkoutState.createAccountSec = false;
            $scope.checkoutState.accountPasswordSec = false;
            $scope.checkoutState.retryEmailSec = false;
            $scope.checkoutState.sumitCartErrorSec = false;
        };

        //Region payment

        $scope.onSubmitCart = function() {
            if (!$scope.shippingRate) {
                $scope.checkoutState.sumitCartErrorSec = true;
                $scope.checkoutState.errorMessage = siteRes.SelectShippingRate;
                return false;
            }

            checkoutSubmitCartSvc.submitOrder($scope.checkoutState, $scope.cartData);

            if (!$scope.checkoutState.sumitCartErrorSec) {
                anchorHelper.setAnchor('paymentAnchor');
            }

            return true;
        };

        //try to submit a card on hpci processed, this method is called externally, from hpci handler
        $scope.onHpciProcessed = function() {
            if ($scope.checkoutState.hpciProcessed === true) {
                //alert('yes');
                checkoutSubmitCartSvc.processCreditCardPayment($scope.checkoutState, $scope.cartData);
            }
        };

        //EndRegion payment

        //Region 3ds

        $scope.verify3Ds = function () {
            return checkoutSubmitCartSvc.verify3Ds($scope.checkoutState);
        };

        //EndRegion 3ds

        $scope.phoneEmailSecDone = function () {
            anchorHelper.setAnchor('shippingMethodAnchor');
            $scope.$broadcast('show-errors-check-validity', 'phoneEmailForm');
            if ($scope.phoneEmailForm.$invalid) {
                return;
            }
            // Note: ReceiverName (name field in the following object) is deprecated 
            // since we have it in the AddressInfo of the shipping object
            var receiverMiscInfo = {
                name: '',
                isGift: $scope.cartData.isGift,
                giftNote: $scope.cartData.giftNote
            };
            checkoutSvc.addReceiverMiscInfoToOrderForm(receiverMiscInfo).$promise.then(
                function() {
                    $scope.checkoutState.phoneEmailSec = false;
                    $scope.checkoutState.contactSec = true;
                    $scope.checkoutState.currentStage = 3;
                },
                function() {
                    console.log('addReceiverMiscInfoToOrderForm fail');
				});
			checkoutSvc.requireCSCValidation().$promise.then(
				
				function (value) {
					$scope.checkoutState.requireCSCValidation = value.requireCsc;
					
				},
				function () {
					console.log('requireCSCValidation fail');
				});

        };

        $scope.togglePassword = function() {

            if ($scope.passwordType === 'password') {
                $scope.passwordType = 'text';
            } else {
                $scope.passwordType = 'password';
            }
        };

        $scope.showAccountPasswordSection = function() {
            $scope.checkoutState.createAccountSec = false;
            $scope.checkoutState.accountPasswordSec = true;
        };

        $scope.submitGuestOrder = function(generateUserId) {
            var customerData = {};
            //when userId provided means user click on register later button, will create account use default value, don't need validation those three fields
            if (generateUserId) {
                customerData.userId = checkoutHelperService.guid();
            } else {
                $scope.$broadcast('show-errors-check-validity', 'accountPasswordForm');
                if ($scope.accountPasswordForm.$invalid) {
                    return;
                }
            }
            //SK: why????
            if ($scope.password.trim() === '') {
                $scope.password = Math.random().toString(36).slice(-8);
            }
            if ($scope.firstName.trim() === '') {
                $scope.firstName = 'Guest';
            }
            if ($scope.lastName.trim() === '') {
                $scope.lastName = 'Guest';
            }
            if ($scope.cartData.phone === undefined || $scope.cartData.phone.trim() === '') {
                //SK: why???? made by JH, changeset 40773
                $scope.cartData.phone = '416-888-9999';
            }
            customerData.email = $scope.cartData.email;
            customerData.phone = $scope.cartData.phone;
            customerData.firstName = $scope.firstName;
            customerData.lastName = $scope.lastName;
            customerData.password = $scope.password;
            customerData.address = addressDataHelper.getBillingData();

            checkoutSubmitCartSvc.submitGuestOrder(customerData, $scope.checkoutState, $scope.cartData);
        };

        $scope.paymentMethods = {
            showCreditCardChecked: $scope.checkoutState.paymentType === 1,
            showPayPalChecked: $scope.checkoutState.paymentType === 2,
            showAffirmChecked: $scope.checkoutState.paymentType === 3,
        };

        $scope.togglePaymentMethod = function(paymentType) {
            $scope.checkoutState.paymentType = paymentType;
            if ($scope.paymentMethods.showCreditCardChecked === true && $scope.paymentMethods.showPayPalChecked === true && $scope.paymentMethods.showAffirmChecked === true) {
                switch (paymentType) {
                case 1:
                    $scope.paymentMethods.showPayPalChecked = false;
                    $scope.paymentMethods.showAffirmChecked = false;
                    break;
                case 2:
                    $scope.paymentMethods.showCreditCardChecked = false;
                    $scope.paymentMethods.showAffirmChecked = false;
                    break;
                case 3:
                    $scope.paymentMethods.showCreditCardChecked = false;
                    $scope.paymentMethods.showPayPalChecked = false;
                     break;
                default:
                    break;
                }
            }
            $scope.checkoutState.paymentSec = true;
        };

        $scope.receiverSecDone = function() {
            $scope.$broadcast('show-errors-check-validity', 'receiverForm');
            if ($scope.receiverForm.$invalid) {
                return;
            } else {
            
                var data = $scope.addressData.shippingData;
                shippingService.updateShippingAddress(data.country.countryId, data.postalCode, false, data.province, data.city, data.address1, data.address2, data.address3, data.FirstName, data.LastName).$promise.then(
                    function() {
                        anchorHelper.setAnchor('shippingMethodAnchor');
                        $scope.checkoutState.receiverSec = false;
                        $scope.checkoutState.deliverToSec = true;
                        $scope.checkoutState.shippingMethodSec = true;
                    });
            }
        };

        $scope.editShippingInfo = function() {
            $scope.checkoutState.addressSec = true;
            $scope.checkoutState.receiverSec = false;
            $scope.checkoutState.deliverToSec = false;
            $scope.checkoutState.shippingMethodSec = false;
            $scope.checkoutState.shipUsingSec = false;
            $scope.checkoutState.phoneEmailSec = false;
        };

        $scope.shippingMethodSecDone = function() {
            anchorHelper.setAnchor('contactAnchor');
            $scope.checkoutState.shippingMethodSec = false;
            $scope.checkoutState.shipUsingSec = true;
            $scope.checkoutState.phoneEmailSec = true;
        };

        $scope.editShippingUsing = function() {
            $scope.checkoutState.shippingMethodSec = true;
            $scope.checkoutState.shipUsingSec = false;
            $scope.checkoutState.phoneEmailSec = false;
        };

        $scope.getShippingRates = function(shippingData) {
            var shippingCountry = shippingData.country.countryId;
            var shippingProvince = shippingData.province || '';
            var shippingPostalCode = shippingData.postalCode;
            shippingService.getShippingRates(shippingCountry, shippingProvince, shippingPostalCode, false).$promise.then(function(value) {
                $scope.shippingRates = value.shippingRates;
                // default is nothing selected
                if ($scope.shippingRate) {
                    angular.forEach($scope.shippingRates, function(rate) {
                        if (rate.Id == $scope.shippingRate) {
                            $scope.shippingMethod = rate.Name;
                            $scope.checkoutState.shippingSelected = true;
                        }
                    });
                    $scope.updateShippingRate({ Name: $scope.shippingMethod, Id: $scope.shippingRate }, true);
                }
            });
        };

        $scope.updateShippingRate = function(rate, initLoad) {
            //update cart shipper id & reload cart data after rate change
            shippingService.updateShippingRate($scope.shippingRate).$promise.then(
                function() {
                    cartDataStorageService.loadCartData();
                    //broadcast shippingRateChanged event, then summary controller can do something when shipping rate change(current beheavior is fade in: could change the behavior by modify fade-in class in common.less)
                    //and the ship via will display rate base on this
                    if (!initLoad) {

                        $scope.shippingMethod = rate.Name;
                        $scope.checkoutState.shippingSelected = true;

                        appObserver.broadcast('shippingRateChanged', rate);
                    }
                }
            );
        };
    }
]);
;
'use strict';

/**
 * this is service that stores cart data, shared across multiple cart directives
 */


angular.module('checkout').factory('CheckoutDataStorageService',
    function () {
        var checkoutState = {
            billingSec: false,
            checkoutState: true,
            createAccountSec: false,
            accountPasswordSec: false,
            sumitCartErrorSec: false,
            paymentSec: true,
            addressSec: false,
            receiverSec: false,
            deliverToSec: false,
            shipUsingSec: false,
            shippingMethodSec: false,
            phoneEmailSec: false,
            contactSec: false,
            billingAddressSec: false,

            show3Ds: false,
            threeDsNotifierUrl: '',
            pass3Ds: false,

            hpciProcessed: false,

            shippingSelected: false,

            currentStage: 2,
            paymentType: 0,

            errorMessage: '',

            giftCards: [],

            creditCardData: {}
        };

        return {
            checkoutState: checkoutState
        };
    });;
'use strict';

/**
* This is platform implemented checkout
*/
angular.module('checkout').directive('odCheckout',
    ['$window', 'appUrlBuilder', 'CheckoutSvc', 'NavigationService',
    function ($window, appUrlBuilder, checkoutSvc, navigationService) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutTemplateUrl'),
        scope: {
        },
        controller: 'CheckoutCtrl',
        link: function (scope) {
            scope.confirmCancel = function () {
                checkoutSvc.confirmDialog();
            };
            scope.goBackToStore = function () {
                navigationService.navigate(appUrlBuilder.buildUrl('homePageUrl'));
            };
    
            scope.preloadData();
        }
    };
}]);;
'use strict';

/**
* This directive is displaying gift cards on the page.
*/
angular.module('checkout').directive('odCheckoutGiftCard', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        replace: true,
        scope: {
            cartTotal:'='
        },
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutGiftCardTemplateUrl'),
        controller: 'GiftCardCtrl'
    };
}]);;
'use strict';

/**
 * this is the helper service for checkout
 */


angular.module('checkout').factory('CheckoutHelperService',
    function () {

        var addressDataMap = function (addressInfo) {
            var address = {
                Nickname: addressInfo.Nickname,
                FirstName: addressInfo.FirstName,
                LastName: addressInfo.LastName,
                address1: addressInfo.Address1,
                address2: addressInfo.Address2,
                address3: addressInfo.Address3,
                city: addressInfo.City,
                province: addressInfo.Province,
                postalCode: addressInfo.PostalCode,
                country: {
                    countryCode: addressInfo.Country.CountryCode,
                    countryId: addressInfo.Country.CountryId,
                    countryName: addressInfo.Country.CountryName
                }
            };
            return address;
        };

        var guid = function () {
            function _p8(s) {
                var p = (Math.random().toString(16) + '000000000').substr(2, 8);
                return s ? '-' + p.substr(0, 4) + '-' + p.substr(4, 4) : p;
            }

            return _p8() + _p8(true) + _p8(true) + _p8();
        };

        var getGiftCardAmounts = function (giftCards) {
            var totalValidAmount = 0;

            angular.forEach(giftCards, function (item) {
                totalValidAmount += Number(item.Amount);
            });
            return roundNum(totalValidAmount);
        };

        var roundNum = function (num) {
            return Math.round(num * 100) / 100;
        };

        return {
            addressDataMap: addressDataMap,
            guid: guid,
            getGiftCardAmounts: getGiftCardAmounts,
            roundNum: roundNum
        };
    });;
'use strict';

/**
* This directive is loading cart data and displaying giftcards on the page.
*/
angular.module('checkout').directive('odCheckoutPaymentTab', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        replace: true,
        priority: 1001,
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutPaymentTabTemplateUrl')
    };
}]);;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('checkout').directive('odCheckoutPayPal', ['appUrlBuilder',
    function (appUrlBuilder) {
        return {
            restrict: 'A',
            replace: true,
            templateUrl: appUrlBuilder.buildTemplateUrl('CheckOutPaypalTemplateUrl')
        };
    } ] );;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('checkout').directive('odCheckoutReceiver', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        replace: true,
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutReceiverTemplateUrl')
    };
}]);;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('checkout').directive('odCheckoutShippingMethod', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        replace: true,
        templateUrl: appUrlBuilder.buildTemplateUrl('checkoutShippingMethodTemplateUrl')
    };
}]);;
'use strict';

/**
* This directive is loading shipping rate data and displaying shipping rate by radio buttons group on the page.
*/
angular.module('checkout').directive('odCheckoutShippingRate', [
    'appUrlBuilder',
    function(appUrlBuilder) {
        return {
            restrict: 'A',
            replace: true,
            templateUrl: appUrlBuilder.buildTemplateUrl('checkoutShippingRateTemplateUrl')
        };
    }
]);;
'use strict';

/**
 * Responsible for all cart specific communication with the server
 */
angular.module('checkout').factory('CheckoutSubmitCartSvc', ['$q', '$timeout', 'appUrlBuilder', 'siteConfiguration', 'siteRes', 'CheckoutSvc', 'CheckoutDataStorageService', 'spinnerFactory', 'NavigationService', 'AddressDataHelper', 'CheckoutCreditCardValidationService','accountSvc','CartDataStorageService','CheckoutHelperService',
    function ($q, $timeout, appUrlBuilder, siteConfiguration, siteRes, checkoutSvc, checkoutDataStorageService, spinnerFactory, navigationService, addressDataHelper, checkoutCreditCardValidationService, accountSvc, cartDataStorageService, checkoutHelperService) {
    
        var addPaypalOption = function (signedIn, giftCards) {
            spinnerFactory.show();
            if (signedIn) {
                if (giftCards !== undefined && giftCards !== null && giftCards.length > 0) {
                    addGiftCardsPayPalPaymentThenSubmit(giftCards);
                } else {
                    addPayPalPaymentThenSubmit();
                }
            } else {
                checkoutDataStorageService.checkoutState.createAccountSec = true;
                spinnerFactory.hide();
            }
        };

        var addPayPalPaymentThenSubmit = function () {
            var deferred = $q.defer();
            checkoutSvc.addPaypalOption().$promise.then(
                function () {
                    navigationService.navigate(appUrlBuilder.buildUrl('PayPalSubmitCartUrl'));
                }, function (error) {
                    spinnerFactory.hide();
                    deferred.reject(error);
                });
        };

        var addGiftCardsPayPalPaymentThenSubmit = function (giftCards) {
            addGiftCards(giftCards).then(
                function () {
                    spinnerFactory.hide();
                    addPayPalPaymentThenSubmit();
                },
                function (error) {
                    spinnerFactory.hide();
                    checkoutDataStorageService.checkoutState.sumitCartErrorSec = true;
                    checkoutDataStorageService.checkoutState.errorMessage = error;
                });
        };

        var addGiftCards = function (giftCardData) {
            var deferred = $q.defer();
            spinnerFactory.show();
            checkoutSvc.addGiftCardsToOrderForm(giftCardData).$promise.then(
                function (value) {
                    deferred.resolve(value);
                }, function (error) {
                    deferred.reject(error);
                });
            return deferred.promise;
        };
        
        var addGiftCardsCreditCardPaymentThenSubmit = function (giftCards, creditCardData, cartData) {
            addGiftCards(giftCards).then(
                function() {
                    spinnerFactory.hide();
                    addCreditCardPaymentThenSubmit(creditCardData, cartData);
            },
                function(error) {
                    spinnerFactory.hide();
                    checkoutDataStorageService.checkoutState.sumitCartErrorSec = true;
                    checkoutDataStorageService.checkoutState.errorMessage = error;
                });
        };

        var addCreditCardPaymentThenSubmit = function(creditCardData, cartData) {
            addCreditCardPayment(creditCardData).then(
                function() {
                    spinnerFactory.hide();
                    var paymentInfo = {
                        guestAccount: !cartData.signedIn,
                        paymentType: 1,
                        paymentAdded: true,
                        ignore3Ds: false
                    };
                    submitCart(paymentInfo);
                },
                function (error) {
                    spinnerFactory.hide();
                    checkoutDataStorageService.checkoutState.sumitCartErrorSec = true;
                    checkoutDataStorageService.checkoutState.errorMessage = siteRes.SubmitCartFailByCreditCard + error;
                    console.log(error);
                });
        };

        var addCreditCardPayment = function(creditCardData) {
            var deferred = $q.defer();
            spinnerFactory.show();
            checkoutSvc.addCreditCardPayment(creditCardData).$promise.then(
                function(value) {
                    deferred.resolve(value);
                }, function(error) {
                    deferred.reject(error);
                });
            return deferred.promise;
        };

        var payByGiftValidate = function (giftCards, cartData) {
            if (giftCards !== undefined && giftCards !== null && giftCards.length > 0) {
                if (checkoutHelperService.getGiftCardAmounts(giftCards) >= Number(cartData.total)) {
                    return true;
                } else {
                    checkoutDataStorageService.checkoutState.errorMessage = siteRes.GiftCardAmountLessThanCartTotal;
                    return false;
                }
            } else {
                checkoutDataStorageService.checkoutState.errorMessage = siteRes.EnterGiftCard;
                return false;
            }
        };

        var addGiftCardsPaymentThenSubmit = function(giftCards, cartData) {
            var paymentInfo = {
                guestAccount: !cartData.signedIn,
                paymentType: 0,
                paymentAdded: true,
                ignore3Ds: false
            };
            if (payByGiftValidate(giftCards, cartData)) {
                addGiftCards(giftCards).then(
                    function() {
                        spinnerFactory.hide();
                        submitCart(paymentInfo);
                    },
                    function(error) {
                        spinnerFactory.hide();
                        checkoutDataStorageService.checkoutState.sumitCartErrorSec = true;
                        checkoutDataStorageService.checkoutState.errorMessage = siteRes.SubmitCartFailByCreditCard +error;
                    });
            } else {
                submitCartFail(paymentInfo);
            }
        };



        var submitCartFail = function (paymentInfo, error) {
            checkoutDataStorageService.checkoutState.sumitCartErrorSec = true;
            if (error) {
                checkoutDataStorageService.checkoutState.errorMessage = error;
            }
            if (paymentInfo.guestAccount && paymentInfo.paymentType == 1) {
                console.log('submit cart return value is false, need error message here');
            } else {
                //paypal fa
            }
            checkoutDataStorageService.checkoutState.billingSec = false;
            checkoutDataStorageService.checkoutState.paymentSec = true;
            checkoutDataStorageService.checkoutState.createAccountSec = false;
            checkoutDataStorageService.checkoutState.accountPasswordSec = false;
            checkoutDataStorageService.checkoutState.retryEmailSec = false;
        };

        var checkOrderStatus = function (orderId, tries) {
            var deferred = $q.defer();
            checkoutSvc.checkOrderStatus(orderId).$promise.then(
                function (value) {
                    if (value.Success === true) {
                        navigationService.navigate(appUrlBuilder.buildUrl('confirmationPageUrl') + '/' + value.OrderId);
                    } else {
                        if (tries === 0) {
                            navigationService.navigate(appUrlBuilder.buildUrl('confirmationPageUrl') + '/' + value.OrderId);
                        } else {
                            $timeout(function () {
                                tries = tries - 1;
                                checkOrderStatus(value.OrderId, tries);
                            }, 5000);
                        }
                    }
                },
                function (error) {
                    spinnerFactory.hide();
                    submitCartFail({ guestAccount: false, paymentType: 1, ignore3Ds: true }, error);
                    deferred.reject(error);
                }
            );
            return deferred.promise;
        };

        var submitCart = function (paymentInfo) {
            var deferred = $q.defer();
            spinnerFactory.show(siteRes.OrderSubmitMessage);
            checkoutSvc.submitCart(paymentInfo.ignore3Ds).$promise.then(
                function (value) {
                    if (value.Success === true) {
                        //Check order status and wait until it successfully
                        checkOrderStatus(value.OrderId, siteConfiguration.timesToCheckSubmitedOrder);
                    } else {
                        spinnerFactory.hide();
                        if (value.Enforce3Ds === true) {
                            checkoutDataStorageService.checkoutState.show3Ds = true;
                            checkoutDataStorageService.checkoutState.threeDsNotifierUrl = checkoutSvc.getThreeDsNotifierUrl();
                        } else {
                            submitCartFail(paymentInfo, value.ErrorMessage);
                        }
                    }
                },
                function (error) {
                    spinnerFactory.hide();
                    //to do : go back to payment section in checkoutpage
                    deferred.reject(error);
                }
            );
            return deferred.promise;
        };
       
        var addAffirmOption = function (signedIn) {
            spinnerFactory.show();
            if (signedIn) {
              
                    addAffirmPaymentThenSubmit();
               
            } else {
                checkoutDataStorageService.checkoutState.createAccountSec = true;
                spinnerFactory.hide();
            }
        };


        var addAffirmPaymentThenSubmit = function () {
            var deferred = $q.defer();
                checkoutSvc.submitAffirm().$promise.then(
          function (value) {
             
                  var _affirm_config = {
                      public_api_key: value.apikey,// jshint ignore:line
                      script: "https://cdn1-sandbox.affirm.com/js/v2/affirm.js"// jshint ignore:line
                  };
                  (function (l, g, m, e, a, f, b) { var d, c = l[m] || {}, h = document.createElement(f), n = document.getElementsByTagName(f)[0], k = function (a, b, c) { return function () { a[b]._.push([c, arguments]) } }; c[e] = k(c, e, "set"); d = c[e]; c[a] = {}; c[a]._ = []; d._ = []; c[a][b] = k(c, a, b); a = 0; for (b = "set add save post open empty reset on off trigger ready setProduct".split(" ") ; a < b.length; a++) d[b[a]] = k(c, e, b[a]); a = 0; for (b = ["get", "token", "url", "items"]; a < b.length; a++) d[b[a]] = function () { }; h.async = !0; h.src = g[f]; n.parentNode.insertBefore(h, n); delete g[f]; d(g); l[m] = c })(window, _affirm_config, "affirm", "checkout", "ui", "script", "ready");// jshint ignore:line
                  // Use your live public API Key and https://cdn1.affirm.com/js/v2/affirm.js script to point to Affirm production environment.
                 
                  affirm.checkout(value.data);// jshint ignore:line
                  affirm.checkout.post();// jshint ignore:line
                  spinnerFactory.hide();
             
          },
          function (error) {
            
              spinnerFactory.hide();
              deferred.reject(error);
          }
      );
           
          
        };
       

        var readyToPay = function (checkoutState, cartData) {
      
            if(checkoutState.paymentType === 1 || checkoutState.paymentType === 0) {
                if (checkoutState.paymentType === 1 && checkoutCreditCardValidationService.isCardValid(checkoutState) || checkoutState.paymentType === 0) {
                    processCreditCardPayment(checkoutState, cartData);
                }
            }
            if (checkoutState.paymentType === 2) {
                addPaypalOption(cartData.signedIn, checkoutState.giftCards);
            }

            if (checkoutState.paymentType === 3) {
                addAffirmOption(cartData.signedIn);
            }
        };

        //public methods

        var submitGuestOrder = function(customerData, checkoutState, cartData) {
            accountSvc.createAccount(customerData).$promise.then(
                function() {
                    checkoutSvc.addAddressDataToOrderForm(addressDataHelper.getShippingData(), addressDataHelper.getBillingData(), addressDataHelper.getSameAsShippingAddress()).$promise.then(
                        function() {
                            if (!addressDataHelper.getSameAsShippingAddress()) {
                                cartDataStorageService.loadCartData();
                            }
                            checkoutState.accountPasswordSec = false;
                            checkoutState.retryEmailSec = false;
                            if (checkoutState.giftCards !== undefined && checkoutState.giftCards.length > 0) {
                                if (checkoutState.paymentType === 0) {
                                    addGiftCardsPaymentThenSubmit(checkoutState.giftCards, cartData);
                                }
                                if (checkoutState.paymentType === 1) {
                                    addGiftCardsCreditCardPaymentThenSubmit(checkoutState.giftCards, checkoutState.creditCardData, cartData);
                                }
                                if (checkoutState.paymentType === 2) {
                                    addGiftCardsPayPalPaymentThenSubmit(checkoutState.giftCards);
                                }
                                if (checkoutState.paymentType === 3) {
                                    addAffirmPaymentThenSubmit();
                                }

                                
                            } else {
                                if (checkoutState.paymentType === 1) {
                                    addCreditCardPaymentThenSubmit(checkoutState.creditCardData, cartData);
                                }
                                if (checkoutState.paymentType === 2) {
                                    addPayPalPaymentThenSubmit();
                                }
                                if (checkoutState.paymentType === 3) {
                                    addAffirmPaymentThenSubmit();
                                }
                            }
                        }, function(error) {
                            console.log(error);
                        });

                }, function(error) {
                    //todo when create account fail let user reEnter email if email exists already
                    console.log(error);
                    checkoutState.accountPasswordSec = false;
                    checkoutState.retryEmailSec = true;
                });
        };

        var submitOrder = function(checkoutState, cartData) {
            if (checkoutState.paymentType === 0) {
                if (cartData.signedIn) {
                    checkoutState.paymentSec = false;
                    checkoutState.billingSec = true;
                    addGiftCardsPaymentThenSubmit(checkoutState.giftCards, cartData);
                } else {
                    if (payByGiftValidate(checkoutState.giftCards, cartData)) {
                        readyToPay(checkoutState, cartData);
                    } else {
                        checkoutState.sumitCartErrorSec = true;
                    }
                }
            } else {
                readyToPay(checkoutState, cartData);
            }
        };

        var processCreditCardPayment = function(checkoutState, cartData) {
            if (checkoutState.paymentType === 1 && checkoutSvc.hpciEnabled() === true && checkoutState.hpciProcessed === false) {
                checkoutSvc.processHpci(function(e) {
                    checkoutSvc.alertDialog(e);
                });
            } else {
                //hide payment section show billing section
                checkoutState.paymentSec = false;
                checkoutState.billingSec = true;
                if (cartData.signedIn) {
                    if (addressDataHelper.getSameAsShippingAddress()) {
                        checkoutSvc.addAddressDataToOrderForm(addressDataHelper.getShippingData(), addressDataHelper.getBillingData(), addressDataHelper.getSameAsShippingAddress()).$promise.then(
                            function() {
                                addGiftCardsCreditCardPaymentThenSubmit(checkoutState.giftCards, checkoutState.creditCardData, cartData);
                            }, function(error) {
                                console.log(error);
                            });
                    } else {
                        addGiftCardsCreditCardPaymentThenSubmit(checkoutState.giftCards, checkoutState.creditCardData, cartData);
                    }
                } else {
                    //show create account section  when payment info added
                    checkoutState.createAccountSec = true;
                }
            }
        };

        var verify3Ds = function(checkoutState) {
            var deferred = $q.defer();
            checkoutSvc.verifyThreeDs().$promise.then(
                function(value) {
                    if (value.submitCart === true) {
                        checkoutState.show3Ds = false;
                        checkoutState.pass3Ds = true;
                        submitCart({ guestAccount: false, paymentType: 1, ignore3Ds: true });
                    } else {
                        checkoutState.sumitCartErrorSec = true;
                        checkoutState.billingSec = false;
                        checkoutState.paymentSec = true;
                        checkoutState.createAccountSec = false;
                        checkoutState.accountPasswordSec = false;
                        checkoutState.retryEmailSec = false;
                        checkoutState.show3Ds = false;
                        checkoutState.pass3Ds = false;
                        checkoutSvc.alert3DsError();
                        checkoutState.threeDsNotifierUrl = '';
                    }
                    deferred.resolve(value);
                }, function(error) {
                    deferred.reject(error);
                });
            return deferred.promise;
        };

        return {
            processCreditCardPayment: processCreditCardPayment,
            verify3Ds: verify3Ds,
            submitGuestOrder: submitGuestOrder,
            submitOrder: submitOrder
        };
    }
]);;
'use strict';

/**
 * Responsible for all cart specific communication with the server
 */
angular.module('checkout').factory('CheckoutSvc', ['$resource', 'appUrlBuilder', 'siteRes', 'DialogService', 'NavigationService',
    function ($resource, appUrlBuilder, siteRes, dialogService, navigationService) {

        var resource = $resource(appUrlBuilder.buildUrl('checkoutApiUrl'), null, {
            'submitCart': { method: 'GET', url: appUrlBuilder.buildUrl('submitCartApiUrl'), isArray: false, responseType: 'json' },
            'checkOrderStatus': { method: 'GET', url: appUrlBuilder.buildUrl('checkOrderStatusApiUrl'), isArray: false, responseType: 'json' },
            'addCreditCardPayment': { method: 'PUT', url: appUrlBuilder.buildUrl('addCreditCardPaymentUrl'), isArray: false, responseType: 'json' },
            'addPayPalOption': { method: 'PUT', url: appUrlBuilder.buildUrl('addPayPalOptionUrl'), isArray: false, responseType: 'json' },
            'getCreditCardTypes': { method: 'GET', url: appUrlBuilder.buildUrl('getCreditCardTypesApiUrl'), isArray: true, responseType: 'json' },
			'verifyThreeDs': { method: 'GET', url: appUrlBuilder.buildUrl('threeDsVerifyApiUrl'), isArray: false, responseType: 'json' },
			'requireCSCValidation': { method: 'GET', url: appUrlBuilder.buildUrl('requireCSCValidationApiUrl'), isArray: false, responseType: 'json' },
            'getGiftCardSettings': { method: 'GET', url: appUrlBuilder.buildUrl('getGiftCardSettingsApiUrl'), isArray: false, responseType: 'json' },
            'getOrderFormGiftcards': { method: 'GET', url: appUrlBuilder.buildUrl('getOrderFormGiftcardsApiUrl'), isArray: true, responseType: 'json' },
            'getOrderFormPayments': { method: 'GET', url: appUrlBuilder.buildUrl('getOrderFormPaymentsApiUrl'), isArray: true, responseType: 'json'},
            'getGiftCardBalance': { method: 'GET', url: appUrlBuilder.buildUrl('getGiftCardBalanceApiUrl'), isArray: false, responseType: 'json' },
            'addGiftCardsToOrderForm': { method: 'PUT', url: appUrlBuilder.buildUrl('addGiftCardsToOrderFormApiUrl'), isArray: false, responseType: 'json' },
            'addReceiverMiscInfoToOrderForm': { method: 'PUT', url: appUrlBuilder.buildUrl('addReceiverMiscInfoToOrderFormApiUrl'), isArray: false, responseType: 'json' },
            'addAddressDataToOrderForm': { method: 'PUT', url: appUrlBuilder.buildUrl('addAddressDataToOrderFormApiUrl'), isArray: false, responseType: 'json' },
            'submitAffirm': { method: 'GET', url: appUrlBuilder.buildUrl('submitAffirmUrl'), isArray: false, responseType: 'json' },
});

        return {
            submitCart: function (ignore3Ds) {
                return resource.submitCart({ignore3Ds: ignore3Ds});
            },
            submitAffirm: function () {
                return resource.submitAffirm();
            },

            checkOrderStatus: function (orderId) {
                return resource.checkOrderStatus({ orderId: orderId });
            },
            addCreditCardPayment: function (card) {
                return resource.addCreditCardPayment(card);
            },
            addPaypalOption: function () {
                return resource.addPayPalOption();
            },
            getCreditCardTypes: function () {
                return resource.getCreditCardTypes();
            },
            confirmDialog: function () {
                dialogService.show({
                    title: siteRes.CheckoutReally,
                    message: siteRes.CheckoutCancelMessage,
                    buttons: [
                        {
                            label: siteRes.CheckoutGoback,
                            cssClass: 'btn-primary',
                            action: function (dialog) {
                                dialog.close();
                            }
                        }, {
                            label: siteRes.CheckoutSaveforlater,
                            cssClass: 'btn-default',
                            action: function () {
                                navigationService.navigate(appUrlBuilder.buildUrl('homePageUrl'));
                            }
                        }
                    ]
                });
            },
            hpciEnabled: function () {
                //Instead of make another call to WebApi we just check if the 'sendHPCI' function exists.
                return (typeof (window.sendHPCI) == 'function');
			},
			requireCSCValidation: function () {
				
				return resource.requireCSCValidation();
			},
			

            processHpci: function (callBack) {
                    window.sendHPCI(callBack);
            },
            alertDialog: function (errorMessage) {
                dialogService.alert(errorMessage);
            },
            verifyThreeDs: function () {
                return resource.verifyThreeDs();
            },
            getThreeDsNotifierUrl: function () {
                return appUrlBuilder.buildUrl('threeDsNotifierUrl');
            },
            getThreeDsVerificationUrl: function () {
                return appUrlBuilder.buildUrl('threeDsVerifierUrl');
            },
            getGiftCardSettings: function () {
                return resource.getGiftCardSettings();
            },
            parseQueryString:function(querystring, key) {
                key = key.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
                var regex = new RegExp('[\\?&]' + key + '=([^&#]*)'),
                    results = regex.exec(querystring);
                return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
            },
            getOrderFormPayments: function () {
                return resource.getOrderFormPayments();
            },
            getOrderFormGiftcards: function () {
                return resource.getOrderFormGiftcards();
            },
            getGiftCardBalance: function (cardNumber, cardPin) {
                return resource.getGiftCardBalance({ cardNumber: cardNumber, cardPin: cardPin });
            },
            addGiftCardsToOrderForm: function (cards) {
                return resource.addGiftCardsToOrderForm(cards);
            },
            addReceiverMiscInfoToOrderForm: function (receiverMiscInfo) {
                return resource.addReceiverMiscInfoToOrderForm(receiverMiscInfo);
            },
            addAddressDataToOrderForm: function (shippingAddress, billingAddress, sameAsShippingAddress) {
                return resource.addAddressDataToOrderForm({ shippingAddress: shippingAddress, billingAddress: billingAddress, sameAsShippingAddress: sameAsShippingAddress
        });
            },
            alert3DsError:function() {
                dialogService.alert(siteRes.ThreeDSAuthFailedMessage);
            },
           
        };
    }
]);;
'use strict';
angular.module('checkout')
    .controller('CreditCardCtrl', ['$scope', '$q', 'CheckoutSvc', 'siteRes', 'AddressDataHelper', 'CartDataStorageService', 'CheckoutDataStorageService', 'CheckoutCreditCardValidationService', 'anchorHelper',
    function ($scope, $q, checkoutSvc, siteRes, addressDataHelper, cartDataStorageService, checkoutDataStorageService, checkoutCreditCardValidationService, anchorHelper) {

        $scope.checkoutState = checkoutDataStorageService.checkoutState;
        $scope.cartData = cartDataStorageService.cartData;
        $scope.card = checkoutCreditCardValidationService.card;

        $scope.initalize = function () {

            $scope.identityName = 'creditCardCtrl';

            $scope.checkoutState.creditCardData.cardNumber = '';
            $scope.checkoutState.creditCardData.expireMonth = 1;
            $scope.checkoutState.creditCardData.expireYear = 2014;
            $scope.checkoutState.creditCardData.cardValidation = '';
            $scope.checkoutState.creditCardData.name = '';

            $scope.useShippingAddress = true;

            $scope.CreditCardInputType = 'password';
            $scope.CvvInputType = 'password';

            $scope.isCardNumberValid = true;
            $scope.isExpireMonthValid = true;
            $scope.isExpireYearValid = true;
            $scope.isCardTypeValid = true;
            $scope.isCardValidationValid = true;
            $scope.isNameValid = true;

            $scope.monthes = [
                { id: 1, name: siteRes.li_Jan },
                { id: 2, name: siteRes.li_Feb },
                { id: 3, name: siteRes.li_Mar },
                { id: 4, name: siteRes.li_Apr },
                { id: 5, name: siteRes.li_May },
                { id: 6, name: siteRes.li_Jun },
                { id: 7, name: siteRes.li_Jul },
                { id: 8, name: siteRes.li_Aug },
                { id: 9, name: siteRes.li_Sep },
                { id: 10, name: siteRes.li_Oct },
                { id: 11, name: siteRes.li_Nov },
                { id: 12, name: siteRes.li_Dec }
            ];

            $scope.years = [];
            var startLYear = new Date().getFullYear();
            for (var i = 0; i < 10; i++) {
                $scope.years.push(startLYear);
                startLYear = startLYear + 1;
            }

            $scope.getCreditCardTypes();
            $scope.hpciEnabled = checkoutSvc.hpciEnabled();
        };

        $scope.cardType = null;
        $scope.onCardTypeChanged = function() {
             if ($scope.cardType === null) {
                $scope.checkoutState.creditCardData.cardTypeId = 0;
                $scope.checkoutState.creditCardData.cardType = '';
             } else {
                $scope.checkoutState.creditCardData.cardTypeId = $scope.cardType._id;
                $scope.checkoutState.creditCardData.cardType = $scope.cardType._cardType;
            }
            $scope.checkoutState.creditCardType = $scope.cardType;

            $scope.isCardTypeValid = checkoutCreditCardValidationService.validateCardType($scope.checkoutState);
        };

        $scope.month = null;
        $scope.onMonthChanged = function() {
            if ($scope.month !== null && $scope.month !== undefined) {
                $scope.checkoutState.creditCardData.expireMonth = $scope.month.id;
            } else {
                $scope.checkoutState.creditCardData.expireMonth = 0;
            }

            $scope.isExpireMonthValid = checkoutCreditCardValidationService.validateMonth($scope.checkoutState);
        };

        $scope.onYearChanged = function () {
            $scope.isExpireYearValid = checkoutCreditCardValidationService.validateYear($scope.checkoutState);
        };

        $scope.onCvvChanged = function () {
            $scope.isCardValidationValid = checkoutCreditCardValidationService.validateCardValidation($scope.checkoutState);
        };

        $scope.onNameChanged = function () {
            $scope.isNameValid = checkoutCreditCardValidationService.validateName($scope.checkoutState);
        };

        $scope.onCardNumberChanged = function (allowEmpty) {
            $scope.isCardNumberValid  = checkoutCreditCardValidationService.validateCardNumber($scope.checkoutState, allowEmpty);
        };

        //Functions
        $scope.getCreditCardTypes = function () {
            var deferred = $q.defer();
            checkoutSvc.getCreditCardTypes().$promise.then(
                function (value) {
                    $scope.cardTypes = value;
                    $scope.cardType = null; //$scope.cardTypes[0];
                }, function (error) {
                    deferred.reject(error);
                });
            return deferred.promise;
        };

        $scope.switchCCMask = function () {
            if ($scope.CreditCardInputType === 'password') {
                $scope.CreditCardInputType = 'text';
            } else {
                $scope.CreditCardInputType = 'password';
            }

        };

        $scope.switchCvvMask = function () {
            if ($scope.CvvInputType === 'password') {
                $scope.CvvInputType = 'text';
            } else {
                $scope.CvvInputType = 'password';
            }
        };

        $scope.billingAddressDone = function (data) {
            addressDataHelper.updateBillingData(data);
            checkoutSvc.addAddressDataToOrderForm(addressDataHelper.getShippingData(), addressDataHelper.getBillingData(), addressDataHelper.getSameAsShippingAddress()).$promise.then(
                function() {
                    if (!addressDataHelper.getSameAsShippingAddress()) {
                        cartDataStorageService.loadCartData();
                    }
                }, function(error) {
                    console.log(error);
                });
            anchorHelper.setAnchor('billingAnchor');
            
            $scope.checkoutState.billingAddressSec = true;
        };

        $scope.editBillingInfo = function() {
            $scope.checkoutState.billingAddressSec = false;
        };
        $scope.sameAsShipping = function (value) {
            $scope.billingSame = value;
            addressDataHelper.updateSameAsShippingAddress(value);
        };


        $scope.initalize();
    }]);;
'use strict';

angular.module('checkout').controller('GiftCardCtrl', 
    ['$scope', '$q', 'appUrlBuilder', 'CheckoutSvc', 'siteConfiguration', 'AppObserver', 'CheckoutDataStorageService', 'CheckoutHelperService',
    function ($scope, $q, appUrlBuilder, checkoutSvc, siteConfiguration, appObserver, checkoutDataStorageService, checkoutHelperService) {

    $scope.imageUrl = appUrlBuilder.buildUrl('giftCardGrayImageUrl');

    $scope.data = {};
    $scope.checkoutState = checkoutDataStorageService.checkoutState;
    $scope.data.cardNumber = '';
    $scope.data.pin = '';

    $scope.giftCardSetting = {};

    $scope.cardNumber = '';
    $scope.balance = 0;
    $scope.amountToApply = 0;
    $scope.applyType = 'all';
    $scope.pin = '';
    $scope.editCardNumber = '';
    $scope.isAmountValid = true;

    $scope.isGiftCardValid = true;
    $scope.isGiftCardBalanceZero = false;
    $scope.balanceOverAmount = false;

    $scope.loadGiftCardSetting = function () {
        var deferred = $q.defer();
        checkoutSvc.getGiftCardSettings().$promise.then(
             function (value) {

                 $scope.giftCardSetting.EnableGiftCard = value.EnableGiftCard;
                 $scope.giftCardSetting.EnablePinSupport = value.EnablePinSupport;
                 $scope.giftCardSetting.EnableMultipleGiftCard = value.EnableMultipleGiftCard;
                 if (value.EnableMultipleGiftCard === true) {
                     $scope.giftCardSetting.MaxCardsSupported = value.MaxCardsSupported;
                 } else {
                     $scope.giftCardSetting.MaxCardsSupported = 1;
                 }
                 deferred.resolve(value);
             }, function (error) {
                 deferred.reject(error);
             });
        return deferred.promise;
    };

    $scope.getOrderFormGiftcards = function () {
        var deferred = $q.defer();
        checkoutSvc.getOrderFormGiftcards().$promise.then(
             function (value) {
                 $scope.checkoutState.giftCards = value;
                 deferred.resolve(value);
             }, function (error) {
                 deferred.reject(error);
             });
        return deferred.promise;
    };

    $scope.getGiftCardBalance = function () {

        //in case it is in edit mode;
        $scope.editCardNumber = '';
        $scope.isGiftCardValid = true;
        $scope.isGiftCardBalanceZero = false;
        $scope.balanceOverAmount = false;
        if ($scope.data.cardNumber.length === 0 || ($scope.giftCardSetting.EnablePinSupport === true && $scope.data.pin.length === 0)) {
            return null;
        }

        var deferred = $q.defer();
        checkoutSvc.getGiftCardBalance($scope.data.cardNumber, $scope.data.pin).$promise.then(
             function (value) {

                 if (value.Balance === 0) {
                     if (value.Type === 'Approved') {
                         $scope.isGiftCardBalanceZero = true;
                         $scope.isGiftCardValid = true;
                     } else {
                         $scope.isGiftCardBalanceZero = false;
                         $scope.isGiftCardValid = false;
                     }

                 } else {
                     $scope.balance = value.Balance;
                     $scope.applyType = 'all';

                     var totalGcAmount = $scope.getGiftCardAmounts();
                     if ($scope.roundNum(value.Balance) > $scope.roundNum($scope.cartTotal - totalGcAmount)) {
                         $scope.amountToApply = $scope.roundNum($scope.cartTotal - totalGcAmount);
                         $scope.applyType = '';
                         $scope.balanceOverAmount = true;

                     } else {
                         $scope.amountToApply = value.Balance;

                     }

                     $scope.cardNumber = $scope.data.cardNumber;
                     $scope.data.cardNumber = '';
                     $scope.pin = $scope.data.pin;
                     $scope.data.pin = '';
                 }
                 deferred.resolve(value);
             }, function (error) {
                 $scope.isGiftCardValid = false;
                 deferred.reject(error);
             });
        return deferred.promise;
    };

    $scope.addGiftCard = function () {
        $scope.updateGiftCard($scope.cardNumber, $scope.pin, $scope.amountToApply, $scope.balance);
        $scope.clearAddGiftCard();
    };

    $scope.clearAddGiftCard = function () {
        $scope.balance = 0;
        $scope.pin = '';
        $scope.amountToApply = 0;
        $scope.cardNumber = '';
    };

    $scope.updateGiftCard = function (cardNumber, pin, amountToApply, balance) {
        if ($scope.checkoutState.giftCards === undefined) {
            $scope.checkoutState.giftCards = [];
        }
        var totalValidAmount = $scope.getGiftCardAmounts();

        if (amountToApply > balance) {
            amountToApply = balance;
        }

        amountToApply = $scope.roundNum(amountToApply);
        var updated = false;
        for (var i = 0; i < $scope.checkoutState.giftCards.length; i++) {
            if ($scope.checkoutState.giftCards[i].CardNumber === cardNumber) {
                if (amountToApply <= 0) {
                    $scope.checkoutState.giftCards.splice(i, 1);
                } else {
                    $scope.checkoutState.giftCards[i].Pin = pin;

                    if ($scope.cartTotal < totalValidAmount) {
                        amountToApply = amountToApply - (totalValidAmount - $scope.cartTotal);
                    }

                    $scope.checkoutState.giftCards[i].Amount = $scope.roundNum(amountToApply);
                    $scope.checkoutState.giftCards[i].Balance = balance;

                    appObserver.broadcast('giftCardBlinkListener', {});

                }
                updated = true;
                break;
            }
        }

        if (!updated && amountToApply > 0) {
            if ($scope.cartTotal - totalValidAmount < amountToApply) {
                amountToApply = $scope.roundNum($scope.cartTotal - totalValidAmount);
            }
            if (amountToApply > 0) {
                var giftCard = { CardNumber: cardNumber, Pin: pin, Amount: amountToApply, Balance: balance };
                $scope.checkoutState.giftCards.push(giftCard);
                appObserver.broadcast('giftCardBlinkListener', {});


            }
        }

        $scope.editCardNumber = '';

    };

    $scope.editGiftCard = function (cardNumber) {
        $scope.editCardNumber = cardNumber;
        $scope.cardNumber = '';
    };

    $scope.changeApplyTypeToEmpty = function () {
        $scope.applyType = '';
    };

    $scope.getGiftCardAmounts = function () {
        return checkoutHelperService.getGiftCardAmounts($scope.checkoutState.giftCards);
    };

    $scope.$watch('data.cardNumber', function (newValue) {

        if (newValue.length > 0 && (!$scope.giftCardSetting.EnablePinSupport || $scope.data.pin.length > 0)) {
            $scope.imageUrl = appUrlBuilder.buildUrl('giftCardImageUrl');
        } else {
            $scope.imageUrl = appUrlBuilder.buildUrl('giftCardGrayImageUrl');
        }
    });

    $scope.$watch('data.pin', function (newValue) {

        if (newValue.length > 0 && $scope.data.cardNumber.length > 0) {
            $scope.imageUrl = appUrlBuilder.buildUrl('giftCardImageUrl');
        } else {
            $scope.imageUrl = appUrlBuilder.buildUrl('giftCardGrayImageUrl');
        }
    });

    $scope.$watch('applyType', function (newValue) {
        if (newValue === 'all') {
            $scope.amountToApply = $scope.balance;
        }
    });

    $scope.$watch('amountToApply', function (newValue) {
        var totalGcAmount = $scope.getGiftCardAmounts();

        if ($scope.roundNum(newValue) > $scope.roundNum($scope.balance) || $scope.roundNum(newValue) > $scope.roundNum($scope.cartTotal - totalGcAmount)) {
            $scope.isAmountValid = false;
        } else {
            $scope.isAmountValid = true;

        }
    });

    $scope.roundNum = function (num) {
        return checkoutHelperService.roundNum(num);
    };

    //Initialize
    $scope.loadGiftCardSetting();
    $scope.getOrderFormGiftcards();


}
]);;
'use strict';
/**
 * Responsible for most behaviour within the Account Module such as:
 */
angular.module('account')
    .controller('accountCtrl', ['$scope', '$q', '$modal', 'accountSvc', 'appUrlBuilder', 'NavigationService', 'siteConfiguration', 'PasswordHelper',
    function ($scope, $q, $modal, accountSvc, appUrlBuilder, navigationService, siteConfiguration, passwordHelper) {

        $scope.newCustomer = {};
        $scope.serverErrorMsg = '';
        $scope.addressDone = null;
        $scope.isDisabled = true; // create account button's status (enabled or disabled)

        $scope.phoneNumberRegex = siteConfiguration.phoneNumberRegex;
        $scope.firstNameChangedInit = false;
        $scope.lastNameChangedInit = false;
        $scope.emailChangedInit = false;
        $scope.emailValidInit = false;
        $scope.phoneChangedInit = false;
        $scope.passwordChangedInit = false;

        //for address form to use to decide whether or not automatically trigger done button click event without user clicks after user clicks on validate button
        $scope.triggerDoneButtonEvent = true;

        $scope.validateModel = function () {
            $scope.serverErrorMsg = '';

            var firstNameNotEmpty = false;
            var lastNameNotEmpty = false;
            var emailNotEmpty = false;
            var emailValidFormat = false;
            var phoneNotEmpty = false;
            var passwordNotEmpty = false;

            if ($scope.newCustomer.firstName) {
                firstNameNotEmpty = true;
                if (!$scope.firstNameChangedInit) {
                    $scope.firstNameChangedInit = true;
                }
            }

            if ($scope.newCustomer.lastName) {
                lastNameNotEmpty = true;
                if (!$scope.lastNameChangedInit) {
                    $scope.lastNameChangedInit = true;
                }
            }

            if ($scope.newCustomer.email) {
                emailNotEmpty = true;
                if (!$scope.emailChangedInit) {
                    $scope.emailChangedInit = true;
                }

                // email validation check
                emailValidFormat = $scope.isEmailAddress($scope.newCustomer.email);
                $scope.emailValidInit = emailValidFormat;
            }

            if ($scope.newCustomer.phone) {
                phoneNotEmpty = true;
                if (!$scope.phoneChangedInit) {
                    $scope.phoneChangedInit = true;
                }
            }

            if ($scope.newCustomer.password) {
                passwordNotEmpty = true;
                if (!$scope.passwordChangedInit) {
                    $scope.passwordChangedInit = true;
                }
            }

            // set isDisabled(create button status)
            if (firstNameNotEmpty && lastNameNotEmpty && emailNotEmpty && phoneNotEmpty && passwordNotEmpty && emailValidFormat && $scope.addressDone !== null) {
                $scope.isDisabled = false;
            }
            else {
                $scope.isDisabled = true;
            }         
        };

        $scope.isEmailAddress = function(str) {
            var pattern = siteConfiguration.emailRegex;
            return pattern.test(str); // returns a boolean 
        };


        $scope.$watch('addressDone', function () {
            $scope.validateModel();
        });

        // event handler from address directive
        $scope.customerAddressDone = function (data) {
            if ($scope.newCustomer) {
                $scope.newCustomer.address = data;
            }

            //enable create account button
            $scope.addressDone = data;
        };

        // event handler from address directive
        $scope.customerAddressEdit = function () {
            //disable create account button
            $scope.addressDone = null;
        };

        $scope.createAccount = function (itemData) {

            itemData.returnUrl = '';
            if ($scope.returnUrl) {
                var objFromJson = angular.fromJson($scope.returnUrl);
                if (objFromJson && objFromJson.key) {
                    itemData.returnUrl = objFromJson.key;
                }
            }            

            accountSvc.createAccount(itemData).$promise.then(
                function (data) { // success
                    $scope.serverErrorMsg = '';
                    if (data.returnUrl) {
                        navigationService.navigate(data.returnUrl);
                    } else {
                        navigationService.navigate(appUrlBuilder.buildUrl('mainPageMyAccountUrl'));
                    }
                },
                function (failMessage) {
                    //failure
                    $scope.isDisabled = true;

                    // note: if serverErrorMsg not empty, then error message will be presented from resource file to the view.
                    // below is just for developer's purpose
                    $scope.serverErrorMsg = failMessage.statusText + ' [ ' + failMessage.data + ' ] ';
                }
            );
        };

        $scope.togglePasswordView = function (inputName) {
            passwordHelper.TogglePasswordView(inputName);
        };
    }
]);;
'use strict';

/**
 * this is account control....
 */

angular.module('account').directive('odAccount', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildUniqueTemplateUrl('createAccountTemplateUrl'),
        scope: {
            // returnUrl: '=returnUrl'
            returnUrl: '@'
        },
        controller: 'accountCtrl',
        replace: true
    };
}]);;
'use strict';
/**
 * Responsible for creating account Form Module specific communication with the server:
 */
angular.module('account').factory('accountSvc', ['$resource', 'appUrlBuilder', 
    function ($resource, appUrlBuilder) {

        var resource = $resource(appUrlBuilder.buildUrl('mainPageMyAccountUrl'), null, {
            'createAccount': { method: 'PUT', url: appUrlBuilder.buildUrl('createAccountUrl'), isArray: false, responseType: 'json' }
        });

        return {
            createAccount: function (data) {
                var args = { email: data.email, password: data.password, firstName: data.firstName, lastname: data.lastName, phone:data.phone, EmailOptIn: data.EmailOptIn, address: data.address, returnUrl: data.returnUrl, userId: data.userId  };
                return resource.createAccount(args);
            }
        };
    }
]);;
'use strict';

angular.module('cart').controller('CouponCtrl', [
    '$scope', 'CartService', 'siteRes',
    function ($scope, cartService, siteRes) {
        $scope.InvalidCouponCode = '';
        $scope.couponCode = '';
        $scope.coupons = '';

        $scope.addCoupon = function () {
            $scope.InvalidCouponCode = '';
            cartService.addCoupon($scope.couponCode).then(function () {
                listCoupons(false);
            });
        };

        $scope.removeCoupon = function (couponCode) {
            cartService.removeCoupon(couponCode).then(function () {
                listCoupons(false);
            });
        };
        
        var listCoupons = function (startup) {
            cartService.listCoupons().then(function (value) {
                if (!startup) {
                    var isFound = $scope.couponCode === ''; //if there is no coupon code - nothing was addded
                    angular.forEach(value, function (v) {
                        if (v.CouponCode === $scope.couponCode) {
                            isFound = true;
                        }
                    });
                    if (!isFound) {
                        $scope.InvalidCouponCode = $scope.couponCode + ' ' + siteRes.IsInvalid;
                    }
                }
                $scope.coupons = value;
                $scope.couponCode = '';
            });
        };

        listCoupons(true);
    }]);
;
'use strict';

/**
* This directive is loading cart data and displaying summary on the page.
*/
angular.module('cart').directive('odCoupon', ['appUrlBuilder', 'CartDataService', function (appUrlBuilder) {
    return {
        restrict: 'A',
        replace: true,
        templateUrl: appUrlBuilder.buildTemplateUrl('couponTemplateUrl'),
        controller: 'CouponCtrl',
        priority: 1001
    };
}]);;
'use strict';

/**
* This is platform implemented confirm page.
*/
angular.module('confirm').directive('odConfirmContact', ['appUrlBuilder',
    function (appUrlBuilder) {
        return {
            restrict: 'A',
            templateUrl: appUrlBuilder.buildTemplateUrl('confirmContactTemplateUrl'),
            scope: {
            },
            controller: 'ContactCtrl'
        };

    }]);;
'use strict';

angular.module('confirm')
    .controller('ConfirmCtrl', ['$scope', 'ConfirmPageDataStorageService', 'CartDataStorageService',
        function ($scope, confirmPageDataStorageService, cartDataStorageService) {
            $scope.error = false;
            $scope.cartData = confirmPageDataStorageService.cartData;
            $scope.loadCartData = function() {
                confirmPageDataStorageService.loadData($scope.orderId).then(
                    function() {
                        cartDataStorageService.sync($scope.cartData, false);
                    },
                    function() {
                        $scope.error = true;
                    });
            };

            //preload cart data
            $scope.loadCartData();
        }
    ]);;
'use strict';

/**
* This is platform implemented confirm page.
*/
angular.module('confirm').directive('odConfirm', ['appUrlBuilder',
    function (appUrlBuilder) {
        return {
            restrict: 'A',
            templateUrl: appUrlBuilder.buildTemplateUrl('confirmPageTemplateUrl'),
            scope: {
               orderId: '@'
            },
            controller: 'ConfirmCtrl'
        };
    
}]);;
'use strict';

/**
* This is order line items listing in the confirm page
*/
angular.module('confirm').directive('odConfirmItemsListing', ['appUrlBuilder', function (appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('confirmItemsListingTemplateUrl'),
        controller: 'ItemsListingCtrl',
        scope: {
        }
    };
}]);;
'use strict';

/**
 * this is service that stores cart data, shared across multiple cart directives
 */

angular.module('confirm').factory('ConfirmPageDataStorageService', ['$q', 'ConfirmSvc',
    function ($q, confirmSvc) {
        var cartData = { items: [] };

        var loadData = function (orderId) {
            var deferred = $q.defer();
            confirmSvc.getOrder(orderId).$promise.then(
                function (freshCartData) {
                    sync(freshCartData, false);
                    deferred.resolve({});
                },
                function (error) { deferred.reject(error); });
            return deferred.promise;
        };

        var sync = function (freshCartData) {
            cartData.total = freshCartData.Total;
            cartData.subtotal = freshCartData.SubTotal;
            cartData.totalShipping = freshCartData.TotalShipping;
            cartData.totalTax = freshCartData.TotalTax;
            cartData.TotalDiscounts = freshCartData.TotalDiscounts;
            cartData.taxes = freshCartData.Taxes;
            cartData.showShippingMarketing = freshCartData.ShowShippingMarketing;
            cartData.signedIn = freshCartData.SignedIn;
            cartData.shippingAddress = freshCartData.ShippingAddress;
            cartData.customer = freshCartData.Customer;
            cartData.items = freshCartData.LineItems;
        };

        return {
            cartData: cartData,
            loadData: loadData,
            sync: sync,
        };

    }]);;
/**
* This is platform implemented confirm page.
*/
angular.module('confirm').directive('odConfirmShipping', ['appUrlBuilder',
    function (appUrlBuilder) {
        return {
            restrict: 'A',
            templateUrl: appUrlBuilder.buildTemplateUrl('confirmShippingTemplateUrl'),
            scope: {
            },
            controller: 'ShippingCtrl'
        };

    }]);;
'use strict';

/**
 * Responsible for order confirmation page to communication with the server
 */
angular.module('confirm').factory('ConfirmSvc', ['$resource', 'appUrlBuilder',
    function ($resource, appUrlBuilder) {

        var resource = $resource(appUrlBuilder.buildUrl('orderConfirmApiUrl'), null, {
            'GetOrder': { method: 'GET', url: appUrlBuilder.buildUrl('GetOrderApiUrl') + '?orderId=:orderId', isArray: false }
        });

        return {
            getOrder: function (orderId) {
                return resource.GetOrder({ orderId: orderId });
            }
        };
    }
]);;
'use strict';

/**
* This is platform implemented confirm via page.
*/
angular.module('confirm').directive('odConfirmVia', ['appUrlBuilder',
    function (appUrlBuilder) {
        return {
            restrict: 'A',
            templateUrl: appUrlBuilder.buildTemplateUrl('confirmViaTemplateUrl'),
            scope: {
            },
            controller: 'ViaCtrl'
        };

    }]);;
'use strict';

angular.module('confirm')
    .controller('ContactCtrl', ['$scope', 'ConfirmPageDataStorageService', function ($scope, confirmPageDataStorageService) {
        $scope.cartData = confirmPageDataStorageService.cartData;
    }]);



;
'use strict';

angular.module('confirm')
    .controller('ItemsListingCtrl', ['$scope', 'ConfirmPageDataStorageService',
        function ($scope, confirmPageDataStorageService) {
            $scope.cartData = confirmPageDataStorageService.cartData;
        }]);;
'use strict';

angular.module('confirm')
    .controller('ShippingCtrl', ['$scope', 'ConfirmPageDataStorageService', function ($scope, confirmPageDataStorageService) {
        $scope.cartData = confirmPageDataStorageService.cartData;
    }]);;
'use strict';

angular.module('confirm')
    .controller('ViaCtrl', ['$scope', 'ConfirmPageDataStorageService', function ($scope, confirmPageDataStorageService) {
        $scope.cartData = confirmPageDataStorageService.cartData;
    }]);;
/*global CartHelper:false */
'use strict';

/**
*This directive is the button to add product item to shopping cart
*/
angular.module('product')
  .directive('odAddtocart', ['siteRes', 'siteConfiguration', 'appUrlBuilder',
      function (siteRes, siteConfiguration, appUrlBuilder) {
          return {
              restrict: 'A',
              replace:true,
              scope: {
                  item:'=',
                  autoship:'='
              },
              templateUrl: appUrlBuilder.buildUniqueTemplateUrl('productAddToCartTemplateUrl'),
              controller: 'ProductAddToCartCtrl',
              link: function (scope) {

                  angular.element('.' + siteConfiguration.AddToCartButtonClassIdentifier).click(function () {
                      var cartHelper;
                      cartHelper = new CartHelper(siteRes, siteConfiguration);
                      var autoshipId = scope.selectedAutoShip.Value !== undefined && scope.selectedAutoShip.Value !== null ? scope.selectedAutoShip.Value.Id : 0;
                      return cartHelper.AddToCart(scope.item.Id, scope.item.ProductId, scope.productData.hasPersonalization, autoshipId, scope.quantity.value, false);
                  });
              }
          };
  }]);;
'use strict';

/**
 * product page add to cart button controller
 */
angular.module('product').controller('ProductAddToCartCtrl', ['$scope', 'ProductDataStorageService', 'siteRes', '$timeout',
    function ($scope, productDataStorageService, siteRes, $timeout) {
        $scope.productData = productDataStorageService.productData;
        $scope.selectedAutoShip = productDataStorageService.selectedAutoShip;
        $scope.quantity = productDataStorageService.quantity;

        //Button text effect
        $scope.buttonText = siteRes.AddToCart;

        $scope.$watch('item.IsInCart', function (newVal, oldVal) {
            if (newVal !== oldVal && !$scope.isUpdateingAddToCartEffect) {
                if (newVal === true) {
                    $scope.buttonText = siteRes.AddAnother;
                } else {
                    $scope.buttonText = siteRes.AddToCart;
                }

            }
        });

        $scope.isUpdateingAddToCartEffect = false;
        $scope.$watch('item.triggerAddToCartEffect', function (newVal, oldVal) {
            if (newVal && newVal !== oldVal) {
                $scope.isUpdateingAddToCartEffect = true;
                $scope.buttonText = siteRes.Added;
                $timeout(function () {
                    $scope.buttonText = siteRes.AddAnother;
                    $scope.isUpdateingAddToCartEffect = false;
                    $scope.$apply();
                }, 2000);

            }
        });

    }]);;
'use strict';

/**
 * set the product configuration
 */
angular.module('product').controller('ProductConfigCtrl', ['$scope', '$modal', 'ProductSvc', 'ProductDataStorageService', 'jQueryService',
    function ($scope, $modal, productSvc, productDataStorageService, jQueryService) {

        //set product data reference to storage.
        $scope.productData = productDataStorageService.productData;
        $scope.selectedAutoShip = productDataStorageService.selectedAutoShip;
        $scope.quantity = productDataStorageService.quantity;
       
        /*
         * Get Product Configuration options Information
         * The Information includes:
         *    Items,
         *    Item Categories,
         *    Item Category Items,
         *    Auto ship information
         */
        productSvc.getProductConfig($scope.productId).$promise.then(function (value) {
         

            if ($scope.defaultItemId) {
                var itemFound = false;
               
                angular.forEach(value.Items, function(i) {
                    if (i.Id === $scope.defaultItemId) {
                        itemFound = true;
                        $scope.selectedItem = i;
                       
                    }
                });
                if (itemFound !== true) {
                    $scope.selectedItem = value.Items[0];
                  
                }
            } else {
                $scope.selectedItem = value.Items[0];
              
            }

            $scope.hasItemCategoryItems = value.HasItemCategoryItems;

            if (!value.HasItemCategoryItems) {
                $scope.productData.selectedItem = $scope.selectedItem;
                $scope.productData.singleUnitPrice = $scope.selectedItem.SingleUnitPrice;
            }

           
            $scope.quantity.value = value.Items[0].MinQty;
            $scope.quantity.min = value.Items[0].MinQty;
            $scope.quantity.max = value.Items[0].MaxQty === null ? 2000000000 : value.Items[0].MaxQty;
           
            $scope.productItems = value.Items;
            $scope.itemCategories = value.ItemCategories;
            angular.forEach($scope.itemCategories, function(cat) {

                if ($scope.defaultItemCategories) {

                    var found = false;
                    angular.forEach($scope.defaultItemCategories, function(defaultCat) {
                        if (defaultCat.CategoryId === cat.Id) {
                            if (cat.Items) {
                                angular.forEach(cat.Items, function(c) {
                                    if (c.Id === defaultCat.CategoryItemId) {
                                        found = true;
                                        cat.item = c;
                                    }
                                });
                            }
                        }
                    });
                    if (found !== true) {
                        cat.item = { };
                    }

                } else {
                    cat.item = {};
                }

            });

            $scope.autoships = value.Autoships;
            $scope.swatchImages = value.SwatchImages;
        });

        /*
         * When The combination of  the item categories changes, it will update the information in description, image and stock check section including:
         *  sale price,
         *  retail price,
         *  web id,
         *  retail price,
         *  image information,
         *  stock item id
         *  
         */
        $scope.handleCategoryItemChange = function () {
           
            var selectedCategories = '';
            var count = 1;
            angular.forEach($scope.itemCategories, function (cat) {

                selectedCategories += cat.item.Id;
                if (count < $scope.itemCategories.length) {
                    selectedCategories += ',';
                }

                count++;

            });
            var isItemExist = false;
            angular.forEach($scope.productItems, function (item) {
            
                var selectedCategoriesArr = selectedCategories.split(',');
                var categoryMappingArr = item.CategoryMapping.split(',');
               
                if (item.CategoryMapping === selectedCategories || (jQueryService(selectedCategoriesArr).not(categoryMappingArr).length === 0 && jQueryService(categoryMappingArr).not(selectedCategoriesArr).length === 0)) {

                     isItemExist = true;

                    $scope.updateBasicInformation(item);
                  

                } 
            });
            if (!isItemExist) {
                $scope.updateBasicInformation(null);
            }

        };

        /*
         * When there is no item category, the drop down list of all the items still display and the index change will update related information including:
         *  sale price,
         *  retail price,
         *  web id,
         *  retail price,
         *  image information,
         *  stock item id
         */
        $scope.handleItemChange = function (selectedItem) {

            $scope.updateBasicInformation(selectedItem);
           
        };

        /*
         * Update description section by selected item
         */
        $scope.updateBasicInformation = function(item) {
            if (item !== null) {
                $scope.selectedItem = item;

                $scope.productData.selectedItem = item;

                $scope.quantity.value = item.MinQty;
                $scope.quantity.min = item.MinQty;
                $scope.quantity.max = item.MaxQty;

                $scope.productData.singleUnitPrice = item.SingleUnitPrice;

                if ($scope.fireSelectedItemChanged) {
                    $scope.fireSelectedItemChanged(item);
                }
            }
        };

        /*
         * event handling the change of swatch images
         */
        $scope.handleSwatchImageChange = function(swatchImgItem) {

            angular.forEach($scope.productData.images, function(img) {
                if (swatchImgItem.ItemImageId === img.Id) {
                    $scope.productData.currentImage = img;
                    angular.element('.zoomImg').attr('src', img.ShowUrl);
                    angular.element('.zoomImg').attr('alt', img.PublicDescription);
                }
            });

            //set selected image in we use config as standalone component and no product data is loaded
            if ($scope.isStandalone === true && !$scope.productData.images) {
                $scope.productData.currentImage = { Id: swatchImgItem.ItemImageId };
            }

            angular.forEach($scope.itemCategories, function(ic) {

                if (ic.Id === swatchImgItem.ItemCategoryId) {
                    angular.forEach(ic.Items, function(item) {
                        if (swatchImgItem.CategoryItemId === item.Id) {
                            ic.item = item;
                            $scope.handleCategoryItemChange();
                        }
                    });

                }
            });
        };
    }
]);;
'use strict';

/**
 * this is product control, container for all product related directives
 */

angular.module('product').directive('odProductConfig', ['$compile', '$http', '$templateCache', 'appUrlBuilder',
    function ($compile, $http, $templateCache, appUrlBuilder) {
        return {
            restrict: 'A',
            priority:1000,
            scope: {
                productId: '=',
                hideQuantity: '=',
                hideAutoship: '=',
                defaultItemCategories: '=',
                defaultItemId: '=',
                onSelectedItemChanged: '&',
                isStandalone: '='
            },
            link: function(scope, element, attrs) {

                var rootUrl = appUrlBuilder.buildUrl('productConfig');
                var childScope;
                attrs.$observe('productId', function(newProductId) {
                    var url = rootUrl + '/' + newProductId;

                    $http.get(url + '?' + new Date().getTime(), { cache: $templateCache }).success(
                        function(html) {

                            if (childScope) {
                                childScope.$destroy();
                            }
                            element.html(html);
                            childScope = scope.$new();
                            childScope.defaultItemCategories = scope.defaultItemCategories;
                            childScope.productId = scope.productId;
                            childScope.hideQuantity = scope.hideQuantity;
                            childScope.defaultItemId = scope.defaultItemId;
                            childScope.fireSelectedItemChanged = function(item) {
                                scope.onSelectedItemChanged({ item: item });
                            };
                            $compile(element.contents())(childScope);
                        });
                });
            }
        };
    }]);;
'use strict';

/**
 * this is service that stores product data, shared across multiple product directives
 */

angular.module('product').factory('ProductDataStorageService', ['$q', '$sce','ProductSvc',
    function ($q, $sce,productSvc) {
        var productData = {};
        var selectedAutoShip = {};
        var quantity = {};

        var loadProductData = function(productId) {

            var deferred = $q.defer();

            productSvc.getProduct(productId).$promise.then(
                function(value) {
                    /*
                     * Description section
                     */
                    productData.id = value.Id;
                    productData.productName = value.ProductName;
                    productData.averageRating = value.AverageRating;
                    productData.ratingNumber = value.RatingNumber;

                    productData.singleUnitPrice = value.SingleUnitPrice;
                    productData.retailPrice = value.RetailPrice;


                    productData.dynamicPromotion = $sce.trustAsHtml(value.DynamicPromotion);

                    productData.shortDescription = value.ShortDescription;
                    productData.customText1 =$sce.trustAsHtml( value.CustomText1);

                    productData.hasPersonalization = value.HasPersonalization;


                    /*
                     * Image section
                     */
             
                    productData.currentImage = value.DefaultImage;
                    if (productData.currentImage === null) {
                        productData.currentImage = {
                            ShowUrl: value.DefaultImageUrl

                    };
                    }
                    if (productData.currentImage.ShowUrl === '') {
                        productData.currentImage.ShowUrl = value.DefaultImageUrl;
                    } 
                    productData.images = value.Images;

                    /*
                     * Tabs section
                     */
                    //Description Tab
                    productData.longDescription = $sce.trustAsHtml(value.LongDescription);

                    //Specification Tab
                    productData.specs = value.Specs;

                    //Reviews Tab
                    productData.ratingBreakdowns = value.RatingBreakdowns;
                    productData.reviews = value.Reviews;

                    //Related Products Tab
                    productData.relatedProductsCount = value.RelatedProductsCount;

                    //Buy Together Tab
                    productData.bundlesCount = value.BundlesCount;

                    productData.isInWishList = value.IsInWishList;
                    productData.firstItemId = value.FirstItemId;
                    //just resolving
                    deferred.resolve({});

                }, function(error) {
                    deferred.reject(error);
                });

            return deferred.promise;
        };

        return {
            productData: productData,
            selectedAutoShip: selectedAutoShip,
            quantity: quantity,
            loadProductData: loadProductData
        };

    }]);;
'use strict';

/**
 * Lists the products' basic information including name, description, price promotion etc
 */
angular.module('product').controller('ProductDescCtrl', ['$scope', 'ProductDataStorageService',
    function ($scope, productDataStorageService) {
       
        //set product data reference to storage.
        $scope.productData = productDataStorageService.productData;
    }
]);;
'use strict';

/**
 * this is product control, container for all product related directives
 */

angular.module('product').directive('odProductDescription', ['$timeout',  'appUrlBuilder',
    function ($timeout, appUrlBuilder) {
    return {
        restrict: 'A',
        transclude: true,
        priority:5,
        templateUrl: appUrlBuilder.buildTemplateUrl('productDescriptionTemplateUrl'),
        controller: 'ProductDescCtrl',
        scope: {
            
            initOnload: '@',
            data: '='
        },
        link: function (scope) {

            var initializeDesc, isInitialized;
            initializeDesc = function () {
                $timeout(function () {
                    scope.productData.isDescRendered = true;
                });
            };
            if (scope.initOnload) {
                isInitialized = false;
                return scope.$watch('data', function (newVal) {
                    if (newVal !== null && !isInitialized) {
                        initializeDesc();
                        isInitialized = true;
                    }
                });
            } else {
                return initializeDesc();
            }
        }
    };
}]);;
'use strict';

/**
 * this is product control, container for all product related directives
 */

angular.module('product').directive('odProduct', ['appUrlBuilder',
    function (appUrlBuilder) {
        return {
            restrict: 'A',
            scope: {
                productId: '@productId'
            },
            templateUrl: function(elem, attrs) {
                return appUrlBuilder.buildUrl('productDetailTemplateUrl') + '/' + attrs.productId;
            },
            controller: 'ProductRootCtrl'
        };
}]);;
'use strict';

/**
 * Lists the products images
 */
angular.module('product').controller('ProductImageCtrl', ['$scope', 'ProductDataStorageService',
    function ($scope, productDataStorageService) {

        //set product data reference to storage.
    
        $scope.productData = productDataStorageService.productData;

        $scope.selectedThumbImageUrl = $scope.productData.currentThumbImageUrl;

    }
]);;
'use strict';

/**
 * this is product image directive, container for product image section
 * working with jquery plugin (jquery.zoom, slick, etc)
 */



angular.module('product').directive('odProductImage', ['$window', '$compile', '$http', '$timeout', 'appUrlBuilder', function ($window, $compile, $http, $timeout, appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: appUrlBuilder.buildTemplateUrl('productImageTemplateUrl'),
        controller: 'ProductImageCtrl',
        priority: 4,
        transclude: true,
        link: function (scope) {
            scope.updateShowImage = function(image) {
                scope.productData.currentImage = image;
                scope.selectedThumbImageUrl = image.ThumbUrl;
                angular.element('.zoomImg').attr('src', image.ShowUrl);
                angular.element('.zoomImg').attr('alt', image.PublicDescription);
            };

            
            scope.onLoad = function() {
                scope.$apply(function () {

                    angular.element('#mainImg').zoom();
                    angular.element('.lightroombox[href!="{{image.ShowUrl}}"]').colorbox({ rel: 'lightroombox', height: '80%', width: '80%' });
                    angular.element('.lightroomboxMain').click(function (e) {
                        var currentShowUrl = angular.element('.lightroomboxMain').attr('href');
                        angular.element('a.lightroombox[href="' + currentShowUrl + '"]').click();
                        e.preventDefault();
                    });

                    scope.productData.isImageRendered = true;

                    scope.imageLoaded = true;
                });
            };
        }
        
      
    };
}]);;
'use strict';

/**
 * When choosing a product for purchase, product personalization is when the end user is asked questions such as an engraving, special instructions, etc.
 * This controller manages the process of asking the questions and processing the answers.
 */
angular.module('product')
    .controller('ProductPersonalizationCtrl', ['$scope', '$modalInstance', 'scopeArguments', 'siteRes',
        function ($scope, $modalInstance, scopeArguments, siteRes) {

            $scope.productId = scopeArguments.productId;
            $scope.itemId = scopeArguments.itemId;
            $scope.itemGuid = scopeArguments.itemGuid;
            $scope.enableItemSelection = scopeArguments.enableItemSelection.toString().toLowerCase() === 'true';
            $scope.hasPersonalization = scopeArguments.hasPersonalization.toString().toLowerCase() === 'true';
            $scope.itemCategories = scopeArguments.itemCategories;

            $scope.optionsTitle = siteRes.Options || 'Options';
            $scope.personalizationTitle = siteRes.Personalization || 'Personalization';

      
            $scope.onSubmit = function (data) {
          
                if ($scope.enableItemSelection===true&& ($scope.selectedItem.Id === undefined || $scope.selectedItem.Id === null)) {
                    return false;
                }
                var result = { selectedItem: $scope.selectedItem, selectedOptions: data };
                    $modalInstance.close(result);
                
            };

            $scope.onCancel = function() {
                $modalInstance.dismiss('cancel');
            };

            $scope.onSubmiteItemSelection = function() {
                $scope.onSubmit({});
            };

            $scope.selectedItem = {};

            $scope.onSelectedItemChanged = function (item) {
                $scope.selectedItem = item;
            };
        }
    ]);;
'use strict';
/**
 * Responsible for controlling the lifecycle of the product personalization window and any communication with the
 * server around the questions/answers.
 */
angular.module('product')
    .factory('ProductPersonalizationService', ['$q', '$modal', 'appUrlBuilder',
        function ($q, $modal, appUrlBuilder) {

            var url = appUrlBuilder.buildUrl('productPersonalizationUrl');

            return {
                openPersonalizationDialog: function (args) {

                    //there is no personalization at all - do not show popup and return immediately
                    if (args.hasPersonalization.toString().toLowerCase() !== 'true' &&
                        args.enableItemSelection.toString().toLowerCase() !== 'true') {

                        var deferred = $q.defer();
                        deferred.resolve({});
                        return deferred.promise;
                    }

                    //productId, itemGuid, hasPersonalization, enableItemSelection
                    var instance = $modal.open({
                        templateUrl: url,
                        controller: 'ProductPersonalizationCtrl',
                        windowClass: 'modal-vertical-centered',
                        backdrop: 'static',
                        resolve: {
                            scopeArguments: function () {
                                return args;
                            }
                        }
                    });

                    return instance.result;
                }
            };
        }
    ]);;
'use strict';

/**
 * Lists the products questions
 */
angular.module('product').controller('ProductQuestionsCtrl', [
    '$scope', 'AppHelper', 'siteRes', 'ProductQuestionsService', 'siteConfiguration',
    function($scope, appHelper, siteRes, productQuestionsService, siteConfiguration) {

        $scope.questionData = {};
        $scope.cancel = function() {
            $scope.$parent.onCancel();
        };
        $scope.formSubmit = function() {
            if ($scope.productQuestionsForm.$valid) {
                var result = appHelper.objectToKeyValuePairArray($scope.questionData);
                $scope.$parent.onSubmit({ data: result });
                }
            else {
                appHelper.setFormDirty($scope.productQuestionsForm);
            }
        };

        $scope.isChecked = function(propertyName) {
            var isFound = false;
            //IE 8 does not support indexOf :(
            angular.forEach($scope.checkedItems, function(value) {
                if (propertyName === value) {
                    isFound = true;
                }
            });

            return isFound;
        };

        $scope.isInvalid = function (inputId) {
            if ($scope.productQuestionsForm[inputId] &&
                $scope.productQuestionsForm[inputId].$invalid === true &&
                $scope.productQuestionsForm[inputId].$pristine === false) {
                return true;
            }
            return false;
        };

        $scope.checkedItems = [];

        if ($scope.$parent.itemGuid) {
            productQuestionsService.getAnsweredPersonalizationQuestionsForItem($scope.$parent.itemGuid).$promise.then(function (data) {
                if (data) {

                    angular.forEach(data, function (dataValue) {
                        var val = dataValue.Value;
                        //check if multi select list

                        if (dataValue.IsMultiselect === true && val.indexOf(siteConfiguration.delimiter) > -1) {
                            val = val.split(siteConfiguration.delimiter);
                        }

                        $scope.questionData[dataValue.Key] = val;

                        if (dataValue.IsCheckbox === true && dataValue.CheckBoxValue === true) {
                            $scope.checkedItems.push(dataValue.Key);
                        }
                    });
                }
            });
        }

}]);;
'use strict';

/**
* This directive is loading product personalization questions and displaying them on the page.
*/
angular.module('product').directive('odProductQuestions', [
    '$compile', '$http', '$templateCache', 'appUrlBuilder',
    function($compile, $http, $templateCache, appUrlBuilder) {
        return {
            restrict: 'A',
            replace: true,
            scope: {
                productId: '=',
                itemGuid: '=',
                onSubmit: '&',
                onCancel: '&'
            },
            link: function(scope, element) {
                var rootUrl = appUrlBuilder.buildUrl('productPersonalizationQuestionsUrl');
                var childScope;

                scope.$watch('productId', function(newProductId) {
                    var url = rootUrl + '/' + newProductId;

                    $http.get(url, {
                        cache: $templateCache //- do not cache for now
                    }).success(
                        function(html) {

                            if (childScope) {
                                childScope.$destroy();
                            }

                            element.html(html);
                            childScope = scope.$new();
                            $compile(element.contents())(childScope);
                         });
                });
            }
        };
    }
]);;
'use strict';
/**
 * Product questions/answers.
 */
angular.module('cart')
    .factory('ProductQuestionsService', [
        '$resource', 'appUrlBuilder', function($resource, appUrlBuilder) {

            var resource = $resource(appUrlBuilder.buildUrl('shoppingCartApiUrl'), null, {
                'getAnsweredPersonalizationQuestionsForItem': { method: 'GET', url: appUrlBuilder.buildUrl('getItemQuestionsUrl') + '/:id', isArray: true, responseType: 'json' },
            });

            return {
                getAnsweredPersonalizationQuestionsForItem: function (itemGuid) {
                    return resource.getAnsweredPersonalizationQuestionsForItem({ id: itemGuid });
                }
            };

        }
    ]);;
'use strict';

/**
 * Get the product details
 */
angular.module('product').controller('ProductRootCtrl',
    ['$scope', '$modal', '$window', '$location', 'ProductDataStorageService', 'siteRes', 'WishListService', 'siteConfiguration', 'appUrlBuilder', 'DialogService', 'NavigationService',
    function ($scope, $modal, $window, $location, productDataStorageService, siteRes, wishListService, siteConfiguration, appUrlBuilder, dialogService, navigationService) {

        $scope.error = false;

        //set the reference of product data to data stored in storage
        $scope.productData = productDataStorageService.productData;

        //pre load product data
        $scope.loadProductData = function (productId) {
            $scope.productId = productId;
            productDataStorageService.loadProductData($scope.productId).then(
                function () {

                }, function (error) {
                    if (error.status === siteConfiguration.errorCodeServerError) {
                        $scope.error = true;
                    }
                });
        };

        $scope.openStoreStock = function () {
            if ($scope.productData.selectedItem.Id === undefined || $scope.productData.selectedItem.Id === null) {
                dialogService.alert(siteRes.StoreInventorySelectItemValidationMessage);

            } else {

                $scope.productData.stockModal = $modal.open({
                    template: '<div class="modalStoreStock" od-product-stock item-id="productData.itemId"></div>',
                });

            }
        };

        $scope.addToWishList = function (itemId) {
            wishListService.addItem(itemId, function () {
                $scope.$apply(function() {
                    $scope.productData.isInWishList = true;
                });
            }, function (request, status, error) {
                if (error == 'Unauthorized') {
                    var baseLen = $location.protocol().length + $location.host().length + siteConfiguration.rootUrl.length + 4;

                    var retUrl = $location.absUrl().substring(baseLen);
                    if (retUrl.indexOf('?') >= 0) {
                        retUrl = retUrl + '&addToWishList=' + itemId;
                    } else {
                        retUrl = retUrl + '?addToWishList=' + itemId;
                    }

                    navigationService.navigate(appUrlBuilder.buildUrl('signInPageUrl') + '?ReturnUrl=' + encodeURIComponent('~/' + retUrl));
                } else {
                    dialogService.alert(error);
                }

            });
        };
    }
    ]);;
'use strict';

/**
*This directive is for store stock check.
*/
angular.module('product')
    .directive('odProductStock', ['$window', '$http', '$modal', 'ProductDataStorageService', 'appUrlBuilder', 'siteConfiguration', 'siteRes', 'StoreLocatorService', 'StoreInventoryService',
      function ($window, $http, $modal, productDataStorageService, appUrlBuilder, siteConfiguration, siteRes, storeLocatorService, storeInventoryService) {
      return {
          restrict: 'A',
          scope: {
              itemId: '='
          },
          link: function (scope, element) {

              //set product data reference to storage.
              scope.productData = productDataStorageService.productData;
              var url = appUrlBuilder.buildUrl('storeStockLocatorTemplateUrl') + '?' + new Date().getTime();

              $http.get(url).success(function (data) {
                  element.html(data);
                  if (storeLocatorService.map === null || storeLocatorService.map === undefined) {
                      storeLocatorService.initialize(54.470038, -98.971875);
                  }
                  angular.element('.locationSubmit').click(function (e) {
                      angular.element('i.spinner').show();
                      var country = angular.element('#Country').val();
                      var postal = angular.element('#Postal').val().replace(/\s+/g, '');
                      var address = angular.element('#Address').val();
                      storeLocatorService.removeAllMarkersAndInfoWindows();

                      storeInventoryService.GetUserLocation(scope.productData.selectedItem.Id, country, postal, address);

                      e.preventDefault();
                  });

                  angular.element('.locationInput').keydown(function (e) {
                      if (e.keyCode === 13) {
                          angular.element('i.spinner').show();
                          var country = angular.element('#Country').val();
                          var postal = angular.element('#Postal').val().replace(/\s+/g, '');
                          var address = angular.element('#Address').val();
                          storeInventoryService.GetUserLocation(scope.itemId, country, postal, address);
                          e.preventDefault();
                      }
                  });

                  angular.element('i.spinner').hide();


                  var options = {
                      enableHighAccuracy: false,
                      timeout: 10000,
                      maximumAge: 0
                  };
                  storeInventoryService.getCurrentPosition(options, scope.productData.selectedItem.Id);

                  angular.element('#btnCancel').click(function () {
                      angular.element('#storeStockMap').css('display', 'none');

                  });

                  angular.element('.closeStoreStock').click(function () {

                      scope.productData.stockModal.dismiss();
                      //scope.productData.stockModal.close();
                  });
              });
          }
      };
  }]);;
'use strict';

/**
 * Responsible for order confirmation page to communication with the server
 */
angular.module('product').factory('ProductSvc', ['$resource', 'appUrlBuilder',
    function ($resource, appUrlBuilder) {

        var resource = $resource(appUrlBuilder.buildUrl('productApiUrl'), null, {
            'getProduct': { method: 'GET', url: appUrlBuilder.buildUrl('getProductApiUrl') + '/:id', isArray: false, responseType: 'json' },
            'voteProductReview': { method: 'PUT', url: appUrlBuilder.buildUrl('voteProductReviewApiUrl'), isArray: false, responseType: 'json' },
            'getProductConfig': { method: 'GET', url: appUrlBuilder.buildUrl('getProductConfigApiUrl') + '/:id', isArray: false, responseType: 'json' }
        });

        return {
          
            getProduct: function (productId) {
                return resource.getProduct({ id: productId });
            },

            voteProductReview: function (productId, reviewId, reviewStatus) {
                var data = { ProductId: productId, ReviewId: reviewId, VoteReportStatus: reviewStatus };
            
                return resource.voteProductReview(data);
            },
            getProductConfig: function (productId) {
                return resource.getProductConfig({ id: productId });
            },
          
        };
    }
]);;
'use strict';

/**
 * set the product tab
 */
angular.module('product').controller('ProductTabsCtrl',
    ['$scope', '$location', 'appUrlBuilder', 'ProductSvc', 'siteRes', 'spinnerFactory', 'siteConfiguration', 'ProductDataStorageService', 'DialogService', 'NavigationService',
function ($scope, $location, appUrlBuilder, productSvc, siteRes, spinnerFactory, siteConfiguration, productDataStorageService, dialogService, navigationService) {

    //set product data reference to storage.
    $scope.productData = productDataStorageService.productData;

    $scope.voteProductReview = function (productId, reviewId, reviewStatus) {
      
        productSvc.voteProductReview(productId,reviewId, reviewStatus).$promise.then(
                function (value) {
                    if (value.Status === 'MARKED') {
                        dialogService.alert(siteRes.YouAlreadyMarkedReview);
                    } else {
                        //refresh views, display the new helpful count
                        $scope.productData.reviews = value.Reviews;
                       
                    }
                }, function (error) {
                    //Not login in yet, direct to login page
                    if (error.status === siteConfiguration.errorCodeUnauthorized) {
                       
                        var returnUrl = $location.absUrl();
                        navigationService.navigate(appUrlBuilder.buildUrl('signInPageUrl') + '?ReturnUrl=' +returnUrl);
                    }
                    //system error happens
                    if (error.status === siteConfiguration.errorCodeServerError) {
                        dialogService.show({
                            title: 'Error',
                            message: error.statusText,
                        });
                    }
                });
    };
}
]);;
'use strict';

/**
 * this is product control, container for all product related directives
 */

angular.module('product').directive('odProductTabs', [
    'appUrlBuilder', function(appUrlBuilder) {
    return {
        restrict: 'A',
        templateUrl: function(elem, attrs) {
                return appUrlBuilder.buildUrl('productTabsTemplateUrl') + '/' + attrs.productId;
        },
        controller: 'ProductTabsCtrl',
        priority: 3
    };
    }
]);;
/*exported WishList, sendWishListToFriend */
'use strict';

/**
 * WishList
 */
var WishList = (function ($, show, hide) {

    //constructor
    function WishList(constants, localization, dialogService) {
        this.constants = constants;
        this.localization = localization;
        this.dialogService = dialogService;
    }

    WishList.prototype.AddItem = function (itemId, onSuccess, onError) {

        var model = JSON.stringify({
            'ItemId': itemId
        });

        $.ajax({
            type: 'POST',
            url: window.rootRel + 'api/WishList/AddItem',
            contentType: 'application/json; charset=utf-8',
            data: model,
            dataType: 'json',
            success: function (data) {
                if (data.Success !== undefined && data.Success) {
                    onSuccess(data);
                }
                else {
                    onError(data);
                }
            },
            error: function (request, status, error) {
                onError(request, status, error);
            }
        });
    };

    WishList.prototype.showEmailFriendDialog = function() {
        var ds = this.dialogService;
        var localizedData = this.localization;
        var resString = this.constants.emailRegex;

        ds.show({
            title: this.localization.EmailFriendTitle,
            message: $('<div>' + this.localization.EmailFriendLabel1 +
                '<br/><textarea class="form-control" id="txtRecipient" rows="5" ></textarea>' +
                '<br/>' + this.localization.EmailFriendLabel2 +
                '<br/><textarea class="form-control" id="txtComments" rows="5"></textarea></div>'),

            buttons: [{
                    label: this.localization.Send,
                    cssClass: 'btn-primary',
                    action: function(dialogItself) {
                        var a = dialogItself.getMessage();
                        var recipients = $(a).find('#txtRecipient')[0].value;
                        var comments = $(a).find('#txtComments')[0].value;

                        if (validateEmail(recipients, ds, localizedData, resString)) {
                            dialogItself.close();
                            show();
                            sendEmailToFriend(recipients, comments, function() {
                                hide();
                                ds.alert(localizedData.EmailWishlistSuccess);
                            }, function() {
                                hide();
                                ds.alert(localizedData.EmailWishlistError);
                            });
                        } //if
                    }
                },
                {
                    label: this.localization.Close,
                    action: function(dialogItself) {
                        dialogItself.close();
                    }
                }
            ]
        });
    };

    var sendEmailToFriend = function (recipients, comments, onSuccess, onError) {
        var model = JSON.stringify({
            'Recipients': recipients,
            'Comments': comments
        });
        $.ajax({
            type: 'POST',
            url: window.rootRel + 'api/WishList/SendEmailToFriend',
            contentType: 'application/json; charset=utf-8',
            data: model,
            dataType: 'json',
            success: function (data) {
                if (data.Success !== undefined && data.Success) {
                    onSuccess();
                }
                else {
                    onError();
                }
            },
            error: function (request, status, error) { // jshint ignore:line
                onError();
            }
        });
    };

    var validateEmail = function (emailStr, ds, localizedData, re) {

        if (!emailStr) {
            ds.alert(localizedData.EmailFriendError1);
            return false;
        }

        var emails = emailStr.split('\n');

        for (var i = 0; i < emails.length; i++) {
            if (emails[i].trim() !== '') {
                var success = re.test(emails[i]);
                if (!success) {
                    ds.alert(localizedData.EmailFriendError2);
                    return false;
                }
            }
        }

        return true;
    };

    return WishList;

})(jQuery, window.openSpinner, window.closeSpinner);

//Use in wish list page
var sendWishListToFriend = function() {
    new WishList(window.globalConstants, window.res, window.BootstrapDialog).showEmailFriendDialog();
    return false;
};
;
'use strict';

/**
 * Responsible for instantiation of WishList javascript service
 */
angular.module('wishList').factory('WishListService',
    ['$window', 'siteConfiguration', 'siteRes', 'DialogService',
    function ($window, siteConfiguration, siteRes, dialogService) {

        var wishListObject = new $window.WishList(siteConfiguration, siteRes, dialogService);

        return {
            addItem: wishListObject.AddItem
        };
    }
]);;
'use strict';

/** This defines all of the entry points for Angular applications.  To add a new module, you need to:
* -Add the angular.module definition below for the application
* -Add the module definition for all of the controllers, services, directives, etc. to modules.js.  This will also define any dependencies between modules.
* -Create a web page with an entry point (typically a div tag) that is the entry point
* -Update the angular.element(document).ready to bootstrap the application
* -Add the routes to app.routes.js
*/
angular.element(document).ready(function () {
    var cart = document.getElementById('appCart');
    if (cart) {
        angular.bootstrap(cart, ['appCart']);
    }

    var checkout = document.getElementById('appCheckout');
    if (checkout) {
        angular.bootstrap(checkout, ['appCheckout']);
    }

    var confirm = document.getElementById('appConfirm');
    if (confirm) {
        angular.bootstrap(confirm, ['appConfirm']);
    }

    var product = document.getElementById('appProduct');
    if (product) {
        angular.bootstrap(product, ['appProduct']);
    }

    var account = document.getElementById('appAccount');
    if (account) {
        angular.bootstrap(account, ['appAccount']);
    }
});

/**
 * App is where all of the Single Page Applications (SPA) are configured and initialized.  See: http://docs.angularjs.org/guide/module
 * 
 * For each of the .run methods, they get executed after the injector is created and are used to kick start the application. 
 * Only instances and constants can be injected in them. This is to prevent further system configuration during application run time.
 * 
 * $rootScope.$state allows the UI to retrieve the current state from within templates.
 * 
 * $state.go provides the default state to start with
 * 
 * $rootScope.layout sets the layout name, which can be used to display different layouts (header, footer etc.)
 * It is based on which page the user is located.
 */
angular.module('appCart', ['cart'])
    .run(['$templateCache', '$rootScope', 'appLogger',
        function ($templateCache, $rootScope, appLogger) {

        appLogger.activate($rootScope);
}]);

angular.module('appCheckout', ['checkout'])
    .run(['$templateCache', '$rootScope', 'appLogger',
        function ($templateCache, $rootScope, appLogger) {

        appLogger.activate($rootScope);
    }]);


angular.module('appConfirm', ['confirm'])
    .run(['$templateCache', '$rootScope', 'appLogger',
        function ($templateCache, $rootScope, appLogger) {

            appLogger.activate($rootScope);

        }]);

angular.module('appProduct', ['product'])
    .run(['$templateCache', '$rootScope', 'appLogger',
        function ($templateCache, $rootScope, appLogger) {

            appLogger.activate($rootScope);

        }]);

angular.module('appAccount', ['account'])
    .run(['$templateCache', '$rootScope', 'appLogger',
        function ($templateCache, $rootScope, appLogger) {

            appLogger.activate($rootScope);

        }]);;
