(function () {
    'use strict';
    /* Initialize the main module */
    var Xapp = angular.module('btApp', ['bw.paging', 'btAutoComplete', 'CapturePlus', 'ui.sortable', 'ordinal', 'btImageUtil', 'btImageUtilV2', 'btimageutilcustom', 'btRecommendation','vcRecaptcha']);

    window.app = Xapp;
    Xapp.constant('BASE_URL', window.location.origin);

    window.app.config( function ($httpProvider) {
        $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
        $httpProvider.useApplyAsync(true);

        $httpProvider.interceptors.push(function ($q) {
            return {
                request: function (config) {
                    return config || $q.when(config);
                },
                response: function (response) {

                    //update cookie time to 30 minutes at every request/activity. 
                    var sessionCookie = $.cookie('sid');
                    if (sessionCookie != null && sessionCookie != undefined)
                    {
                        $.removeCookie('sid');
                        $.cookie('sid', sessionCookie, { path: '/', expires: 30 / 1440 });
                    }
                    return response;
                },
                responseError: function (response) {
                    var responseInfo = {
                        status: response.status,
                        statusText: response.statusText,
                        headers: response.headers && response.headers(),
                        data: response.data,
                        config: response.config
                    };
                   
                    if (response.status === 500) {
                        console.log(response)
                    }
                    return $q.reject(response);
                }
            };
        });

    });
})();;
(function () {
    'use strict';

    /**
     * autocomplete
     * Autocomplete directive for AngularJS
     * By Daryl Rowland
     * https://github.com/darylrowland/angucomplete
     */
    var searchid = new Date().getTime();
    angular.module('btAutoComplete', [])
        .directive('btAutoComplete', function ($parse, $http, $sce, $timeout) {
            return {
                restrict: 'EA',
                scope: {
                    "id": "@id",
                    "placeholder": "@placeholder",
                    "selectedObject": "=selectedobject",
                    "url": "@url",
                    "dataField": "@datafield",
                    "titleField": "@titlefield",
                    "descriptionField": "@descriptionfield",
                    "imageField": "@imagefield",
                    "imageUri": "@imageuri",
                    "inputClass": "@inputclass",
                    "userPause": "@pause",
                    "localData": "=localdata",
                    "searchFields": "@searchfields",
                    "minLengthUser": "@minlength",
                    "matchClass": "@matchclass",
                    "returnkeyios": "@returnkeyios"
                },
                template: ' <div class="tfs-search-box">' +
                    '<form method="post" action="{{dynamicUrl}}">' +
                    '<div class="autocomplete-holder">' +
                    '<div class="autocomplete-search-box-container">' +
                    '<div class="mobile-search-back-btn" ng-click="closeSearchDialog()"><svg xmlns="http://www.w3.org/2000/svg" width="10" height="18"><path fill="#1D1258" fill-rule="evenodd" d="M.213 8.486a.712.712 0 000 1.016l8.35 8.255a.842.842 0 00.595.243.844.844 0 00.595-.243.823.823 0 000-1.176L2.08 8.994l7.673-7.582a.822.822 0 000-1.176.868.868 0 00-1.19 0l-8.35 8.25z"/></svg></div>' +
                    '<input title="{{returnkeyios}}" ng-class="{\'bottom-border-radius-none\': ((searching && searchStr.length >= minLength) || (!searching && (results.length == 0 && searchStr.length >= minLength) && showDropdown) || results.length > 0)}" name="txtAutoSearch' + searchid + '"  maxlength="60"  autocomplete="false"  ng-keyup="$event.keyCode == 13 && headerSearch()"  ng-model="searchStr" type="search" placeholder="Search fragrance & beauty" class="typeAheadSearchInput search-textbox search-textbox-mobile" ng-focus="resetHideResults()" ng-blur="hideResults()" autofocus />' +
                    '<div class="input-group-btn-clear" ng-click="clearSearch(true)" ng-if="searchStr.length > 0"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 15 15"><path fill="#999" fill-rule="evenodd" d="M15 14.308a.687.687 0 0 0-.203-.49l-6.318-6.32 6.318-6.315a.688.688 0 0 0 0-.98.709.709 0 0 0-.98 0L7.5 6.52 1.182.203A.688.688 0 0 0 .692 0a.694.694 0 0 0-.49 1.183L6.52 7.499.202 13.818a.694.694 0 0 0 .98.98L7.5 8.48l6.318 6.317a.693.693 0 0 0 1.183-.49"/></svg></div>' +
                    '<div class="input-group-btn-search hidden-sm hidden-xs" ng-class="{\'tfs-btn-disabled\': (searchStr === null || searchStr.length === 0)}" ng-click="headerSearch()"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#1D1258" fill-rule="evenodd" d="M8.914 16.105h-.04c-3.978 0-7.227-3.233-7.25-7.225a7.169 7.169 0 0 1 2.094-5.11 7.157 7.157 0 0 1 5.096-2.145h.03c3.99 0 7.245 3.223 7.26 7.2.019 3.992-3.208 7.258-7.19 7.28M23.75 23.78a.81.81 0 0 0 .014-1.158c-2.676-2.685-4.564-4.571-6.45-6.459l-.292-.288a77.054 77.054 0 0 0-.851-.839l-.491-.48.107-.142c1.742-2.301 2.326-4.78 1.737-7.366-.81-3.564-3.052-5.856-6.663-6.813a7.716 7.716 0 0 0-.893-.168C9.824.045 9.681.025 9.537 0l-1.38.003c-.113.023-.258.044-.407.067-.313.046-.61.091-.902.17-3.463.923-5.685 3.144-6.607 6.605-.08.294-.124.59-.17.905-.022.148-.045.295-.071.441l.02 1.48c.015.088.03.178.04.268.25 1.872.975 3.476 2.157 4.77 2.257 2.468 5.07 3.427 8.377 2.845 1.373-.244 2.581-.805 3.804-1.767l.14-.111.127.127s4.557 4.57 7.963 7.965a.804.804 0 0 0 1.12.013"/></svg></div>' +
                    '<div ng-style="dropdownHeight" class="autocomplete-dropdown" ng-class="{\'show-block\': ((searching && searchStr.length >= minLength) || (!searching && (results.length == 0 && searchStr.length >= minLength) && showDropdown) || results.length > 0)}">' +
                    '<div class="autocompleting" ng-show="searching && searchStr.length >= minLength">Searching...</div>' +
                    '<div class="autocomplete-searching" ng-show="!searching && (results.length == 0 && searchStr.length >= minLength) && showDropdown">' +
                    '<div class="no-results-header">No results found for "{{searchStr}}"</div>' +
                    '<div class="no-results-header-info">Please check for spelling errors, or try a more general term.</div>' +
                    '</div>' +
                    '<div class="autocomplete-brands" ng-if="brands.length > 0 && results.length > 0 && !searching">' +
                    '<a ng-repeat="brand in brands" class="autocomplete-brands-item" href="{{ brand.slug }}">' +
                    'Shop all <span ng-bind-html="brand.title"></span>' +
                    '</a>' +
                    '</div>' +
                    '<div ng-repeat="result in results" class="autocomplete-results" ng-if="results.length > 0 && $index<resultsToFetch && !searching">' +
                    '<div class="">' +
                    '<a class="tfs-search-link" href="{{result.slug }}">' +
                    '<div class="autocomplete-image-holder" ng-if="imageField">' +
                    '<img ng-srcset="{{result.image}}?h=64 1x, {{result.image}}?h=64&dpr=2 2x" ng-src="{{result.image}}?h=64" alt="{{result.title}}" class="autocomplete-image"/>' +
                    '</div>' +
                    '<div class="autocomplete-title-holder">' +
                    '<div class="autocomplete-title-result" ng-bind-html="result.title"></div>' +
                    '</div>' +
                    '</a>' +
                    '</div>' +
                    '</div>' +
                    '<div class="autocomplete-bestsellers" ng-if="bestSellers.length > 0 && !searching && (results.length == 0 && searchStr.length >= minLength)">You might like some of our bestsellers</div>' +
                    '<div ng-repeat="bestResult in bestSellers" ng-if="bestSellers.length > 0 && !searching && (results.length == 0 && searchStr.length >= minLength)" >' +
                    '<div class="">' +
                    '<a class="tfs-search-link" href="{{bestResult.slug}}">' +
                    '<div class="autocomplete-image-holder" ng-if="imageField">' +
                    '<img ng-srcset="{{bestResult.image}}?h=64 1x, {{bestResult.image}}?h=64&dpr=2 2x" ng-src="{{bestResult.image}}?h=64" alt="bestResult.title" class="autocomplete-image"/>' +
                    '</div>' +
                    '<div class="autocomplete-title-holder">' +
                    '<div class="autocomplete-title-result">{{ bestResult.title }}</div>' +
                    '</div>' +
                    '</a>' +
                    '</div>' +
                    '</div>' +
                    '</div>' +
                    '</div>' +
                    '</div>' +
                    '</form>' +
                    '</div>',

                link: function ($scope, elem, attrs) {
                    $scope.lastSearchTerm = null;
                    $scope.currentIndex = null;
                    $scope.justChanged = false;
                    $scope.searchTimer = null;
                    $scope.hideTimer = null;
                    $scope.searching = false;
                    $scope.pause = 200;
                    $scope.minLength = 2;
                    $scope.searchStr = null;
                    $scope.returnkeyios = "Search";
                    $scope.statWith = '/';
                    $scope.results = [];
                    $scope.bestSellers = [];
                    $scope.brands = [];
                    $scope.brandsToFetch = 3;
                    $scope.resultsToFetch = 10;
                    $scope.bestsellersToFetch = 5;
                    $scope.currentRequest = null;
                    $scope.bestResultsRequest = null;
                    $scope.brandsRequest = null;
                    $scope.showDropdown = false;
                    $scope.dropdownHeight = {"height": "calc(100vh - 66px)"};
                    $scope.dynamicUrl = null;
                    $scope.matchClass = 'autocomplete-highlight';

                    $(document).ready(function () {
                        $(window).on('resize touchstart', function (event) {
                            var attr = $('html').hasClass('overflow-hidden');
                            if (typeof attr !== typeof undefined && attr !== false) {
                                var height = window.innerHeight - 66;
                                $scope.$apply(function () {
                                    $scope.dropdownHeight = {"height": height + "px"};
                                });
                            }
                        }).resize();
                        $(document).on('touchstart', function (event) {
                            var attr = $('html').hasClass('overflow-hidden');
                            if (typeof attr !== typeof undefined && attr !== false) {
                                var target = $(event.target);
                                if ((!target.closest('.typeAheadSearchInput').length && $('.typeAheadSearchInput').is(":visible")) &&
                                    (!target.closest('.input-group-btn-clear').length)) {
                                    $('.typeAheadSearchInput').blur();
                                }
                            }
                        });
                    });

                    $scope.isNewSearchNeeded = function (newTerm, oldTerm) {
                        return newTerm.length >= $scope.minLength && newTerm !== oldTerm;
                    };
                    $scope.headerSearch = function () {
                        if ($scope.searchStr === null || $scope.searchStr.length === 0) {
                            return;
                        }
                        window.location = "//" + window.location.host + "/search?freeText=" + $scope.searchStr.toLowerCase();
                    };

                    $scope.hideResults = function () {
                        var attr = $('html').hasClass('overflow-hidden');
                        // For some browsers, `attr` is undefined; for others,
                        // `attr` is false.  Check for both.
                        if (typeof attr === typeof undefined || attr === false) {
                            $scope.hideTimer = $timeout(function () {
                                $scope.clearSearch(false);
                            }, $scope.pause);
                        }
                    };

                    $scope.closeSearchDialog = function () {
                        var containerMobile = $('.mobileSearch');
                        var containerDesktop = $('.tfs-header-search-bar');
                        if (containerMobile.hasClass('active')) {
                            containerMobile.removeClass("active");
                            containerMobile.find('.typeAheadSearchInput').blur();
                        }
                        if (containerDesktop.hasClass('active')) {
                            containerDesktop.removeClass("active");
                            containerDesktop.find('.typeAheadSearchInput').blur();
                        }
                        $('html, body').removeClass('overflow-hidden');
                        $scope.clearSearch(false);
                    };

                    $scope.resetHideResults = function () {
                        if ($scope.hideTimer) {
                            $timeout.cancel($scope.hideTimer);
                        }
                    };

                    $scope.applyMatchClass = function (text, lookup) {
                        var re = new RegExp(lookup, 'i');
                        var strPart = text.match(re);
                        if (strPart === null) {
                            text = $sce.trustAsHtml(text);
                        } else {
                            text = $sce.trustAsHtml(text.replace(re, '<span class="' + $scope.matchClass + '">' + strPart[0] + '</span>'));
                        }
                        return text;
                    };

                    $scope.clearSearch = function (focus) {
                        $scope.searchStr = null;
                        $scope.lastSearchTerm = null;
                        $scope.showDropdown = false;
                        $scope.currentIndex = null;
                        $scope.results = [];
                        $scope.brands = [];
                        $scope.bestSellers = [];
                        $timeout.cancel($scope.searchTimer);
                        $timeout.cancel($scope.hideTimer);
                        if ($scope.currentRequest != null) {
                            $scope.currentRequest.abort();
                        }
                        if ($scope.brandsRequest != null) {
                            $scope.brandsRequest.abort();
                        }
                        $scope.searching = false;
                        if (focus === true) {
                            $('.typeAheadSearchInput').focus();
                        }
                    };
                    $scope.getBestResults = function () {
                        if ($scope.bestSellers.length > 0) {
                            return;
                        }
                        $scope.bestResultsRequest = $.ajax({
                            type: 'GET',
                            url: '/json/bestsellers',
                            beforeSend: function () {
                                if ($scope.bestResultsRequest != null) {
                                    $scope.bestResultsRequest.abort();
                                }
                            },
                            success: function (data) {
                                // Success
                                if (!data) {
                                    return;
                                }
                                $scope.$apply(function () {
                                    $scope.bestSellers = data.map(function (ele) {
                                        var link = (ele.slug.charAt(0) === '/') ? ele.slug : '/' + ele.slug;
                                        return {
                                            title: ele.brand + ' ' + ele.subBrand + ' ' + ele.name,
                                            slug: link,
                                            image: ele.image
                                        };
                                    }).slice(0, $scope.bestsellersToFetch);
                                    $scope.searching = false;
                                    $scope.showDropdown = true;
                                });
                            },
                            error: function (e) {
                                // Error
                                // console.log("error");
                            }
                        });
                    };

                    $scope.getBrands = function (str) {
                        if (str.length >= $scope.minLength) {
                            $scope.brandsRequest = $.ajax({
                                type: 'GET',
                                url: '/json/brands?q=' + str,
                                beforeSend: function () {
                                    if ($scope.brandsRequest != null) {
                                        $scope.brandsRequest.abort();
                                    }
                                },
                                success: function (data) {
                                    // Success
                                    if (!data) {
                                        return;
                                    }
                                    $scope.$apply(function () {
                                        $scope.brands = data.map(function (ele) {
                                            var link = (ele.link.charAt(0) === '/') ? ele.link : '/' + ele.link;
                                            return {
                                                title: $scope.applyMatchClass(ele.manufacturerName, str),
                                                slug: link
                                            };
                                        }).slice(0, $scope.brandsToFetch);
                                    });
                                },
                                error: function (e) {
                                    // Error
                                }
                            });
                        }
                    };

                    $scope.processResults = function (responseData, str) {
                        if (responseData && responseData.length > 0) {
                            $scope.results = responseData.map(function (result) {
                                var link = (result.slug.charAt(0) === '/') ? result.slug : '/' + result.slug;
                                return {
                                    title: $scope.applyMatchClass(result.name, str),
                                    slug: link,
                                    image: result.image
                                }
                            });
                        } else {
                            $scope.getBestResults();
                            $scope.results = [];
                        }
                        $scope.searching = false;
                        $scope.showDropdown = true;
                        PubSub.publish("search", str, responseData);
                    };
                    PubSub.subscribe('search', function (searchKey, eventData) {

                        var HeroProcess = window.HeroProcess || null;
                        if (HeroProcess)
                            HeroProcess.HeroSearchTransmitter(searchKey);

                        if (eventData != null && dataLayer && typeof omnilytics != 'undefined' && omnilytics) {
                            var data = dataLayer[0];
                            var entity = {'FreeText': searchKey, 'ResultCount': eventData.length};
                            data["Entity"] = JSON.stringify(entity);
                            data["EntityId"] = searchKey;
                            data["EntityName"] = searchKey;
                            data["EntityType"] = "Search";
                            data["EventType"] = "Search";
                            data["Action"] = "search";
                            dataLayer[0] = data;
                            omnilytics.emit('Search', null);

                        }
                    });
                    $scope.getSearchResults = function (str) {
                        if (str.length >= $scope.minLength) {
                            $scope.currentRequest = $.ajax({
                                type: 'GET',
                                url: $scope.url + str,
                                beforeSend: function () {
                                    if ($scope.currentRequest != null) {
                                        $scope.currentRequest.abort();
                                    }
                                },
                                success: function (responseData) {
                                    // Success
                                    $scope.$apply(function () {
                                        if (!responseData) {
                                            $scope.getBestResults();
                                            $scope.results = [];
                                            return;
                                        }
                                        $scope.processResults(responseData.products, str);
                                    });
                                },
                                error: function (e) {
                                    // Error 500 sometimes is returned when server thinks it's a SQL injection attack
                                    // We can still fetch best sellers in that case
                                    if (e.status === 500) {
                                        $scope.getBestResults();
                                        $scope.results = [];
                                    }
                                }
                            });
                        }
                    };

                    $scope.keyPressed = function (event) {
                        $scope.$apply(function (event) {
                            $scope.searching = true;
                            
                                if ($scope.searchStr != null && $scope.searchStr.length > 0) {
                                    $scope.dynamicUrl = "//" + window.location.host + "/search?freeText=" + $scope.searchStr.toLowerCase();
                            }
                            if (event.which !== 13) {
                                if (!$scope.searchStr || $scope.searchStr.length === 0) {
                                    $scope.clearSearch(false);
                                } else if ($scope.searchStr.length < $scope.minLength) {
                                    $scope.results = [];
                                    $scope.brands = [];
                                    if ($scope.currentRequest != null) {
                                        $scope.currentRequest.abort();
                                    }
                                    if ($scope.brandsRequest != null) {
                                        $scope.brandsRequest.abort();
                                    }
                                    $scope.searching = false;
                                } else if ($scope.searchStr.length >= $scope.minLength) {
                                    clearTimeout($scope.searchTimer);
                                    $scope.lastSearchTerm = $scope.searchStr;
                                    $scope.currentIndex = null;
                                    $scope.results = [];
                                    $scope.brands = [];
                                    $scope.searchTimer = setTimeout(function () {
                                        $scope.getBrands($scope.searchStr);
                                        $scope.getSearchResults($scope.searchStr);
                                    }, $scope.pause);
                                }
                            } else {
                                event.preventDefault();
                            }
                        });
                    };

                    elem.find('input').on('keyup', $scope.keyPressed);
                }
            };
        });

}());
;
(function () {
    'use strict';
    angular.module('btImageUtil', [])
        .directive('btImageUtil', function ($parse, $http, $sce) {
            return {
                restrict: 'EA',
                scope: {
                    "imageUrl": "@imageurl",
                    "itemName": "@itemname",
                    "imageType": "@imagetype",
                },
                template: '<picture ng-if="imageUrl!=\'\'">' +
                    '<source media="(min-width: 1440px)" data-srcset="{{imageUrl}}?h={{imageUtil.HiRes_H}}&w={{imageUtil.HiRes_W}}&min-w={{imageUtil.HiRes_W}}&min-h={{imageUtil.HiRes_H}} 1x, {{imageUrl}}?h={{imageUtil.HiRes_H}}&w={{imageUtil.HiRes_W}}&min-w={{imageUtil.HiRes_W}}&min-h={{imageUtil.HiRes_H}}&dpr=2 2x">' +
                    '<source media="(min-width: 1200px)" data-srcset="{{imageUrl}}?h={{imageUtil.Desktop_H}}&w={{imageUtil.Desktop_W}}&min-w={{imageUtil.Desktop_W}}&min-h={{imageUtil.Desktop_H}} 1x, {{imageUrl}}?h={{imageUtil.Desktop_H}}&w={{imageUtil.Desktop_W}}&min-w={{imageUtil.Desktop_W}}&min-h={{imageUtil.Desktop_H}}&dpr=2 2x">' +
                    '<source media="(min-width: 768px)" data-srcset="{{imageUrl}}?h={{imageUtil.Tablet_H}}&w={{imageUtil.Tablet_W}}&min-w={{imageUtil.Tablet_W}}&min-h={{imageUtil.Tablet_H}} 1x, {{imageUrl}}?h={{imageUtil.Tablet_H}}&w={{imageUtil.Tablet_W}}&min-w={{imageUtil.Tablet_W}}&min-h={{imageUtil.Tablet_H}}&dpr=2 2x">' +
                    '<source media="(min-width: 480px)" data-srcset="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}} 1x, {{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}}&dpr=2 2x">' +
                    '<img data-src="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}}" data-srcset="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}} 1x, {{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}}&dpr=2 2x" alt="{{itemName}}" class="image1 omni-img lazyload">' +
                    '</picture>' +
                    '<img  ng-if="imageUrl==\'\'" data-src="/assets/theme/tfs/images/noimagefound.jpg" alt="{{itemName}}" class="img-responsive omni-img lazyload"/ >',
                link: function ($scope, elem, attrs) {
                    $scope.imageUrl = attrs.imageurl;
                    $scope.itemName = attrs.itemname;
                    $scope.imageType = attrs.imagetype;

                    $scope.imageUtil = imageUtils.filter(function (item) {
                        return item.ImageType === $scope.imageType;
                    })[0];

                    $scope.$watch("imageUrl", function (newValue, oldValue) {
                        //This gets called when data changes.
                        if (oldValue !== newValue) {
                            const img = elem.find('img');
                            if (img && img.hasClass('lazyloaded')) {
                                img.removeClass('lazyloaded');
                                img.addClass('ls-reloading');
                                img.addClass('lazyload');
                            }
                        }
                    });
                }
            };
        });

}());;
(function () {
    'use strict';
    angular.module('btimageutilcustom', [])
        .directive('btimageutilcustom', function ($parse, $http, $sce) {
            return {
                restrict: 'A',
                template: '<picture>' +
                    ' <source media="(min-width: 1440px)" data-srcset="{{imageUrl}}?h={{imageUtil.HiRes_H}}&w={{imageUtil.HiRes_W}}">' +
                    '<source media="(min-width: 1200px)" data-srcset="{{imageUrl}}?h={{imageUtil.Desktop_H}}&w={{imageUtil.Desktop_W}}">' +
                    '<source media="(min-width: 768px)" data-srcset="{{imageUrl}}?h={{imageUtil.Tablet_H}}&w={{imageUtil.Tablet_W}}">' +
                    '<source media="(min-width: 480px)" data-srcset="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}">' +
                    '<img data-src="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}" alt="{{itemName}}" class="image1 omni-img lazyload">' +
                    '</picture>',
                replace: true,
                scope: true,
                link: function ($scope, elem, attrs) {
                    $scope.imageUrl = attrs.src;
                    $scope.imageUtil = {
                        HiRes_H: attrs.hiresH, HiRes_W: attrs.hiresW,
                        Desktop_H: attrs.desktopH, Desktop_W: attrs.desktopW,
                        Tablet_H: attrs.tabletH, Tablet_W: attrs.tabletW,
                        Mobile_H: attrs.mobileH, Mobile_W: attrs.mobileW
                    };
                }
            };
        });

}());;
(function () {
    'use strict';
    angular.module('btImageUtilV2', [])
        .directive('btImageUtilV2', function ($parse, $http, $sce) {
            return {
                restrict: 'EA',
                scope: {
                    "imageUrl": "@imageurl",
                    "itemName": "@itemname",
                    "imageType": "@imagetype",
                },
                template: '<picture ng-if="imageUrl!=\'\'">' +
                    '<source media="(min-width: 1440px)" srcset="{{imageUrl}}?h={{imageUtil.HiRes_H}}&w={{imageUtil.HiRes_W}}&min-w={{imageUtil.HiRes_W}}&min-h={{imageUtil.HiRes_H}}&dpr=2 2x, {{imageUrl}}?h={{imageUtil.HiRes_H}}&w={{imageUtil.HiRes_W}}&min-w={{imageUtil.HiRes_W}}&min-h={{imageUtil.HiRes_H}} 1x">' +
                    '<source media="(min-width: 1200px)" srcset="{{imageUrl}}?h={{imageUtil.Desktop_H}}&w={{imageUtil.Desktop_W}}&min-w={{imageUtil.Desktop_W}}&min-h={{imageUtil.Desktop_H}}&dpr=2 2x, {{imageUrl}}?h={{imageUtil.Desktop_H}}&w={{imageUtil.Desktop_W}}&min-w={{imageUtil.Desktop_W}}&min-h={{imageUtil.Desktop_H}} 1x">' +
                    '<source media="(min-width: 768px)" srcset="{{imageUrl}}?h={{imageUtil.Tablet_H}}&w={{imageUtil.Tablet_W}}&min-w={{imageUtil.Tablet_W}}&min-h={{imageUtil.Tablet_H}} 2x, {{imageUrl}}?h={{imageUtil.Tablet_H}}&w={{imageUtil.Tablet_W}}&min-w={{imageUtil.Tablet_W}}&min-h={{imageUtil.Tablet_H}} 1x">' +
                    '<source media="(min-width: 480px)" srcset="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}} 2x, {{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}} 1x">' +
                    '<img data-src="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}}&dpr=2" srcset="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}}&dpr=2 2x, {{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}} 1x" alt="{{itemName}}" class="image1 omni-img lazyload">' +
                    '</picture> ' +
                    '<img ng-if="imageUrl==\'\'" data-src="/assets/theme/tfs/images/noimagefound.jpg"  alt="{{itemName}}" class="img-responsive omni-img lazyload"/ >',
                link: function ($scope, elem, attrs) {
                    $scope.imageUrl = attrs.imageurl;
                    $scope.itemName = attrs.itemname;
                    $scope.imageType = attrs.imagetype;

                    $scope.imageUtil = imageUtils.filter(function (item) {
                        return item.ImageType === $scope.imageType;
                    })[0];
                }
            };
        });

}());;
(function () {
    'use strict';
    angular.module('btRecommendation', [])
        .directive('btRecommendation', function ($parse, $http, $sce, $timeout) {
            return {
                restrict: 'EA',
                scope: {
                    "itemId": "@itemid",
                    "userId": "@userid",
                    "type": "@type",
                    "title": "@title",
                    "noOfItems": "@noofitems",
                    "displayRRPDiscountLabelOn": "@displayrrpdiscountlabelon"
                },
                controller: 'globalCtrl',
                controllerAs: 'gm',
                template: ' <div class="col-sm-12 col-xs-12 gridView"> ' +
                ' <div ng-repeat="prod in recommendProducts" class="col-md-5ths col-sm-5ths col-xs-5ths col-lg-5ths resultContainerRelated ng-scope" > ' +
                '<div class="product-container-panel"> ' +
                '<div class="imagePanel"> ' +
                '<a ng-href="/{{prod.slug}}?rvw=1"> ' +
                '<span class="tooltiptext ng-binding"></span> ' +
                '<bt-image-util imagetype="Product_List_Product_Image" itemname="{{prod.name}}" imageurl="{{prod.image}}" /> ' +
                '</a>' +
                '</div>' +
                '<div class="dataPanel"> ' +
                '<div class="ribbon-info">' +
                '<a ng-href="/{{prod.slug}}?rvw=1"> ' +
                '<span class="brand" ng-bind="prod.brand"></span> ' +
                '<span class="subbrand" ng-bind="prod.subBrand"></span> ' +
                '<span class="product-tfs" ng-bind="prod.name"></span> ' +
                '</a>' +
                '</div>' +
                '<div class="price-info"> ' +
                '<div class="col-sm-8 col-xs-12 no-padding"> ' +
                '<h3> ' +
                    '<span ng-hide="showChangedCurrency" class="ng-binding" ng-bind="prod.price.formatted.withTax"></span> ' +
                    '<span ng-show="showChangedCurrency" class="ng-binding" ng-bind="prod.currencyExchangePrice"></span> ' +
                    '<span  ng-if="!showChangedCurrency && prod.displayRRP" class="sml ng-binding" ng-bind="prod.listPrice.formatted.withTax"></span> ' +
                    '<span ng-if="prod.displayRRP && showChangedCurrency" class="sml ng-binding" ng-bind="prod.currencyExchangeListPrice"></span> ' +
                '</h3> ' +
                '</div> ' +
                '</div> ' +
                '<div class="action-info">' +
                '<button ng-controller=\'globalCtrl as gm\'" ng-if="prod.subscriptionPlanType == \'None\'" type="submit" class="btn-primary animate btn-xl pull-left width-full cart-add-btn recaddtobasket" ng-click="gm.offerCategoryName=prod.classification.mainCategoryName;gm.addToBasket(prod.recordId,1,0)" data-attr=\'{ "id": "{{prod.recordId}}","name":"{{prod.brand}} {{prod.subBrand}}","image":"{{prod.image}}","price":{{prod.priceFrom.raw.withTax}},"brand":"{{prod.brand}}","category":"{{prod.classification.mainCategoryName}}","variant":"{{ prod.name }}","stockCode":"{{ prod.stockCode }}"}\' >Add to Bag</button >' +
                '<button ng-controller=\'subscriptionCtrl as sm\'" ng-if="prod.subscriptionPlanType != \'None\'" type="submit" class="btn-pink animate btn-xl pull-left width-full cart-add-btn recaddtobasket" ng-click="gm.offerCategoryName=prod.classification.mainCategoryName;sm.addSubscriptionToBasket(prod.recordId)"  data-attr=\'{ "id": "{{prod.recordId}}","name":"{{prod.brand}} {{prod.subBrand}}","image":"{{prod.image}}","price":{{prod.priceFrom.raw.withTax}},"brand":"{{prod.brand}}","category":"{{prod.classification.mainCategoryName}}","variant":"{{ prod.name }},"stockCode":"{{ prod.stockCode }}"}\' >Add To Scentaddict List</button >' +
                //'<input type="text">{{prod}}<input>' +
                '</div >' +
                '</div> ' +
                '</div> ' +
                '</div> ' +
                '</div>',
                link: function ($scope, elem, attrs) {

                    $scope.recommendProducts = null;

                    $scope.userId = "";
                    if (attrs.userid) {
                        $scope.userId = attrs.userid;
                    }
                    if (attrs.productdata) {
                        $scope.recommendProducts = userProducts;
                    }

                    var CURRENCY_COOKIE = '_ctcc';
                    $scope.recommendTypes = { Home: "Home", Product: "Product", Basket: "Basket", Personalised: "Personalised", Order: "Order", Promotion: "Promotion", NewForYou: "NewForYou", Popular: "Popular", RecentView: "RecentView" };
                    $http.post('/tfsrecomendation/getrecommendations', { itemId: $scope.itemId, recommedType: $scope.type, noOfItems: $scope.noOfItems, userId: $scope.userId }
                    ).success(function (resp) {
                        $scope.recommendProducts = resp;
                        if ($scope.recommendProducts != null) {
                            angular.forEach($scope.recommendProducts, function (recom) {
                                if ((recom.listPrice.raw.withTax - recom.price.raw.withTax) >= $scope.displayRRPDiscountLabelOn) {
                                    recom.displayRRP = true;
                                }
                                else {
                                    recom.displayRRP = false;
                                }
                              });
                            $scope.showChangedCurrency = false;
                            var changeToCurrencyCode = $.cookie(CURRENCY_COOKIE);
                            if (changeToCurrencyCode) {
                                $http.get('/Home/GetCurrencyExchangeRate' + "?changeToCurrencyCode=" + changeToCurrencyCode).then(function (resp) {
                                    if (resp != null && resp.data != false && resp.data.rate != 1) {
                                        $scope.showChangedCurrency = true;
                                        $scope.selectedCurrencySymbol = resp.data.currencySymbol;
                                        $scope.currencyExchangeRate = resp.data.rate;
                                        angular.forEach($scope.recommendProducts, function (recom) {
                                            recom.currencyExchangePrice = $scope.selectedCurrencySymbol + (recom.price.raw.withTax * resp.data.rate).toFixed(2);
                                            recom.currencyExchangeListPrice = $scope.selectedCurrencySymbol + (recom.listPrice.raw.withTax * resp.data.rate).toFixed(2);
                                        });
                                    }
                                    else
                                        $scope.showChangedCurrency = false;
                                    $.cookie("_ctcc", changeToCurrencyCode, { path: '/', expires: 1000 });
                                });
                            }
                        }
                    }).error(function (err) { console.log(err) });
                }
            };
        });

}());;
/*global angular, DocumentTouch*/
(function () {
    'use strict';

    window.app.directive('ngMagnify', ngMagnify);

    function ngMagnify() {
    return {
      restrict: 'EA',
      replace: true,
      template: '<div class="magnify-container" data-ng-style="getContainerStyle()">' +
                  '<div class="magnify-glass" data-ng-style="getGlassStyle()"></div>' +
                  '<img class="magnify-image" alt="Product" data-ng-src="{{ imageSrc }}"/>' +
                '</div>',
      scope: {
        imageSrc: '@',
        imageWidth: '=',
        imageHeight: '=',
        glassWidth: '=',
        glassHeight: '='
      },
      link: function (scope, element, attrs) {
        var glass = element.find('div'),
          image = element.find('img'),
          el, nWidth, nHeight;

        scope.getContainerStyle = function () {
          return {
            width: (scope.imageWidth) ? scope.imageWidth + 'px' : '',
            height: (scope.imageHeight) ? scope.imageHeight + 'px' : ''
          };
        };

        scope.getGlassStyle = function () {
          return {
            background: 'url(' + scope.imageSrc + ') no-repeat',
            width: (scope.glassWidth) ? scope.glassWidth + 'px' : '',
            height: (scope.glassHeight) ? scope.glassHeight + 'px' : ''
          };
        };

        // if touch devices, do something
        if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
          return;
        }
        element.on('mouseenter', function () {
          el = angular.extend(getOffset(element[0]), {
            width: element[0].offsetWidth,
            height: element[0].offsetHeight
          });
        })
        .on('mousemove', function (evt) {
          if (magnify(evt)) {
            glass.css( magnify(evt) );
          }
        })
        .on('mouseout', function () {
          glass.on('mouseleave', function () {
            glass.css('display', 'none');
          });
        });

        function magnify (evt) {
          var mx, my, rx, ry, px, py, bgp, img;

          if (!nWidth && !nHeight) {
            img = new Image();
            img.onload = function () {
              nWidth = img.width;
              nHeight = img.height;
            };
            img.src = scope.imageSrc;
          } else {
            // IE8 uses evt.x and evt.y
            mx = (evt.pageX) ? (evt.pageX - el.left) : evt.x;
            my = (evt.pageY) ? (evt.pageY - el.top) : evt.y;

            if (mx < el.width && my < el.height && mx > 0 && my > 0) {
              glass.css('display', 'block');
            } else {
              glass.css('display', 'none');
              return;
            }

            rx = Math.round(mx/image[0].offsetWidth*nWidth - glass[0].offsetWidth/2)*-1;
            ry = Math.round(my/image[0].offsetHeight*nHeight - glass[0].offsetHeight/2)*-1;
            bgp = rx + 'px ' + ry + 'px';

            px = mx - glass[0].offsetWidth/2;
            py = my - glass[0].offsetHeight/2;

            // glass.css({ left: px+'px', top: py+'px', backgroundPosition: bgp });
            return { left: px+'px', top: py+'px', backgroundPosition: bgp };
          }
          return;
        }

        function getOffset (el) {
          var offsetLeft = 0,
            offsetTop = 0;

          do {
            if (!isNaN(el.offsetLeft)) {
              offsetLeft += el.offsetLeft;
              offsetTop += el.offsetTop;
            }
          } while (el = el.offsetParent);

          return {
            left: offsetLeft,
            top: offsetTop
          };
        }
      }
    };
  };
})();;
(function () {
	'use strict';

	window.app.directive('formGroupValidation', formGroupValidation);

	function formGroupValidation() {
		return {
			require: '^form',
			replace: true,
			transclude: true,
			template:
				'<div class="has-feedback" ng-class="vm.getValidationClass()">' +
					'<ng-transclude></ng-transclude>' +
					'<input-validation-icons field="vm.field"></input-validation-icons>' +
				'</div>',
			scope: {
				field: '@formGroupValidation'
			},
			controller: controller,
			controllerAs: 'vm',
			link: function (scope, element, attrs, formCtrl) {
				scope.form = formCtrl;
			}
		}
	}

	controller.$inject = ['$scope'];
	function controller($scope) {
		var vm = this;

		vm.field = $scope.field;
		vm.getValidationClass = getValidationClass;

		function getValidationClass() {
			if (!canBeValidated()) return '';

			if (isValid()) return 'has-success';

			return 'has-error';
		}

		function canBeValidated() {
		    if ($scope.form[vm.field] === undefined) return false;
			return ($scope.form[vm.field].$touched || $scope.form.$submitted);
		}

		function isValid() {
			return $scope.form[vm.field].$valid;
		}
	}

})();;
/*
 * Lazy Load Product Images. For use on angular modules only.
 */
(function () {
  function lazyLoad() {

    return {
      link: function (scope, element, attr) {
        scope.productImages = document.querySelectorAll(".c-product-item__img-container__img");

        // create an instance of IntersectionObserver
        //prodWatcher = new IntersectionObserver(function (entries) {
        //  scope.entries = entries;
        //  for (var i = 0, length = scope.entries.length; i < length; i++) {
        //    //when image comes into view, attempt to load image.

        //    if (scope.entries[i].intersectionRatio > 0) {
        //      loadImage(scope.entries[i].target);
        //      prodWatcher.unobserve(entries[i].target);
        //    }

        //  }
        //});
       

        //for (var i = 0, length = scope.productImages.length; i < length; i++) {
        //  prodWatcher.observe(scope.productImages[i]);
        //}

        function loadImage(image) {
          var src = image.getAttribute("data-src");
          
          image.setAttribute("src", src);
          image.onerror = function () {
              image.setAttribute("src", "/assets/theme/tfs/images/noimagefound.jpg");
          }
          
        }

      }

    }
  };
  window.app.directive('lazyLoad', lazyLoad);
})(window.app);
;
/*
 jQuery UI Sortable plugin wrapper

 @param [ui-sortable] {object} Options to pass to $.fn.sortable() merged onto ui.config
 */
angular.module('ui.sortable', [])
  .value('uiSortableConfig', {
      // the default for jquery-ui sortable is "> *", we need to restrict this to
      // ng-repeat items
      // if the user uses
      items: '> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]'
  })
  .directive('uiSortable', [
    'uiSortableConfig', '$timeout', '$log',
    function (uiSortableConfig, $timeout, $log) {
        return {
            require: '?ngModel',
            scope: {
                ngModel: '=',
                uiSortable: '='
            },
            link: function (scope, element, attrs, ngModel) {
                var savedNodes;

                function combineCallbacks(first, second) {
                    var firstIsFunc = first && (typeof first === 'function');
                    var secondIsFunc = second && (typeof second === 'function');
                    if (firstIsFunc && secondIsFunc) {
                        return function () {
                            first.apply(this, arguments);
                            second.apply(this, arguments);
                        };
                    } else if (secondIsFunc) {
                        return second;
                    }
                    return first;
                }

                function getSortableWidgetInstance(element) {
                    // this is a fix to support jquery-ui prior to v1.11.x
                    // otherwise we should be using `element.sortable('instance')`
                    var data = element.data('ui-sortable');
                    if (data && typeof data === 'object' && data.widgetFullName === 'ui-sortable') {
                        return data;
                    }
                    return null;
                }

                function patchSortableOption(key, value) {
                    if (callbacks[key]) {
                        if (key === 'stop') {
                            // call apply after stop
                            value = combineCallbacks(
                              value, function () { scope.$apply(); });

                            value = combineCallbacks(value, afterStop);
                        }
                        // wrap the callback
                        value = combineCallbacks(callbacks[key], value);
                    } else if (wrappers[key]) {
                        value = wrappers[key](value);
                    }

                    // patch the options that need to have values set
                    if (!value) {
                        if (key === 'items') {
                            value = uiSortableConfig.items;
                        } else if (key === 'ui-model-items') {
                            value = uiSortableConfig.items;
                        }
                    }

                    return value;
                }

                function patchUISortableOptions(newVal, oldVal, sortableWidgetInstance) {
                    function addDummyOptionKey(value, key) {
                        if (!(key in opts)) {
                            // add the key in the opts object so that
                            // the patch function detects and handles it
                            opts[key] = null;
                        }
                    }
                    // for this directive to work we have to attach some callbacks
                    angular.forEach(callbacks, addDummyOptionKey);

                    // only initialize it in case we have to
                    // update some options of the sortable
                    var optsDiff = null;

                    if (oldVal) {
                        // reset deleted options to default
                        var defaultOptions;
                        angular.forEach(oldVal, function (oldValue, key) {
                            if (!newVal || !(key in newVal)) {
                                if (key in directiveOpts) {
                                    if (key === 'ui-floating') {
                                        opts[key] = 'auto';
                                    } else {
                                        opts[key] = patchSortableOption(key, undefined);
                                    }
                                    return;
                                }

                                if (!defaultOptions) {
                                    defaultOptions = angular.element.ui.sortable().options;
                                }
                                var defaultValue = defaultOptions[key];
                                defaultValue = patchSortableOption(key, defaultValue);

                                if (!optsDiff) {
                                    optsDiff = {};
                                }
                                optsDiff[key] = defaultValue;
                                opts[key] = defaultValue;
                            }
                        });
                    }

                    // update changed options
                    angular.forEach(newVal, function (value, key) {
                        // if it's a custom option of the directive,
                        // handle it approprietly
                        if (key in directiveOpts) {
                            if (key === 'ui-floating' && (value === false || value === true) && sortableWidgetInstance) {
                                sortableWidgetInstance.floating = value;
                            }

                            opts[key] = patchSortableOption(key, value);
                            return;
                        }

                        value = patchSortableOption(key, value);

                        if (!optsDiff) {
                            optsDiff = {};
                        }
                        optsDiff[key] = value;
                        opts[key] = value;
                    });

                    return optsDiff;
                }

                function getPlaceholderElement(element) {
                    var placeholder = element.sortable('option', 'placeholder');

                    // placeholder.element will be a function if the placeholder, has
                    // been created (placeholder will be an object).  If it hasn't
                    // been created, either placeholder will be false if no
                    // placeholder class was given or placeholder.element will be
                    // undefined if a class was given (placeholder will be a string)
                    if (placeholder && placeholder.element && typeof placeholder.element === 'function') {
                        var result = placeholder.element();
                        // workaround for jquery ui 1.9.x,
                        // not returning jquery collection
                        result = angular.element(result);
                        return result;
                    }
                    return null;
                }

                function getPlaceholderExcludesludes(element, placeholder) {
                    // exact match with the placeholder's class attribute to handle
                    // the case that multiple connected sortables exist and
                    // the placeholder option equals the class of sortable items
                    var notCssSelector = opts['ui-model-items'].replace(/[^,]*>/g, '');
                    var excludes = element.find('[class="' + placeholder.attr('class') + '"]:not(' + notCssSelector + ')');
                    return excludes;
                }

                function hasSortingHelper(element, ui) {
                    var helperOption = element.sortable('option', 'helper');
                    return helperOption === 'clone' || (typeof helperOption === 'function' && ui.item.sortable.isCustomHelperUsed());
                }

                function getSortingHelper(element, ui, savedNodes) {
                    var result = null;
                    if (hasSortingHelper(element, ui) &&
                        element.sortable('option', 'appendTo') === 'parent') {
                        // The .ui-sortable-helper element (that's the default class name)
                        // is placed last.
                        result = savedNodes.last();
                    }
                    return result;
                }

                // thanks jquery-ui
                function isFloating(item) {
                    return (/left|right/).test(item.css('float')) || (/inline|table-cell/).test(item.css('display'));
                }

                function getElementScope(elementScopes, element) {
                    var result = null;
                    for (var i = 0; i < elementScopes.length; i++) {
                        var x = elementScopes[i];
                        if (x.element[0] === element[0]) {
                            result = x.scope;
                            break;
                        }
                    }
                    return result;
                }

                function afterStop(e, ui) {
                    ui.item.sortable._destroy();
                }

                // return the index of ui.item among the items
                // we can't just do ui.item.index() because there it might have siblings
                // which are not items
                function getItemIndex(ui) {
                    return ui.item.parent()
                      .find(opts['ui-model-items'])
                      .index(ui.item);
                }

                var opts = {};

                // directive specific options
                var directiveOpts = {
                    'ui-floating': undefined,
                    'ui-model-items': uiSortableConfig.items
                };

                var callbacks = {
                    receive: null,
                    remove: null,
                    start: null,
                    stop: null,
                    update: null
                };

                var wrappers = {
                    helper: null
                };

                angular.extend(opts, directiveOpts, uiSortableConfig, scope.uiSortable);

                if (!angular.element.fn || !angular.element.fn.jquery) {
                    $log.error('ui.sortable: jQuery should be included before AngularJS!');
                    return;
                }

                function wireUp() {
                    // When we add or remove elements, we need the sortable to 'refresh'
                    // so it can find the new/removed elements.
                    scope.$watchCollection('ngModel', function () {
                        // Timeout to let ng-repeat modify the DOM
                        $timeout(function () {
                            // ensure that the jquery-ui-sortable widget instance
                            // is still bound to the directive's element
                            if (!!getSortableWidgetInstance(element)) {
                                element.sortable('refresh');
                            }
                        }, 0, false);
                    });

                    callbacks.start = function (e, ui) {
                        if (opts['ui-floating'] === 'auto') {
                            // since the drag has started, the element will be
                            // absolutely positioned, so we check its siblings
                            var siblings = ui.item.siblings();
                            var sortableWidgetInstance = getSortableWidgetInstance(angular.element(e.target));
                            sortableWidgetInstance.floating = isFloating(siblings);
                        }

                        // Save the starting position of dragged item
                        var index = getItemIndex(ui);
                        ui.item.sortable = {
                            model: ngModel.$modelValue[index],
                            index: index,
                            source: ui.item.parent(),
                            sourceModel: ngModel.$modelValue,
                            cancel: function () {
                                ui.item.sortable._isCanceled = true;
                            },
                            isCanceled: function () {
                                return ui.item.sortable._isCanceled;
                            },
                            isCustomHelperUsed: function () {
                                return !!ui.item.sortable._isCustomHelperUsed;
                            },
                            _isCanceled: false,
                            _isCustomHelperUsed: ui.item.sortable._isCustomHelperUsed,
                            _destroy: function () {
                                angular.forEach(ui.item.sortable, function (value, key) {
                                    ui.item.sortable[key] = undefined;
                                });
                            }
                        };
                    };

                    callbacks.activate = function (e, ui) {
                        // We need to make a copy of the current element's contents so
                        // we can restore it after sortable has messed it up.
                        // This is inside activate (instead of start) in order to save
                        // both lists when dragging between connected lists.
                        savedNodes = element.contents();

                        // If this list has a placeholder (the connected lists won't),
                        // don't inlcude it in saved nodes.
                        var placeholder = getPlaceholderElement(element);
                        if (placeholder && placeholder.length) {
                            var excludes = getPlaceholderExcludesludes(element, placeholder);
                            savedNodes = savedNodes.not(excludes);
                        }

                        // save the directive's scope so that it is accessible from ui.item.sortable
                        var connectedSortables = ui.item.sortable._connectedSortables || [];

                        connectedSortables.push({
                            element: element,
                            scope: scope
                        });

                        ui.item.sortable._connectedSortables = connectedSortables;
                    };

                    callbacks.update = function (e, ui) {
                        // Save current drop position but only if this is not a second
                        // update that happens when moving between lists because then
                        // the value will be overwritten with the old value
                        if (!ui.item.sortable.received) {
                            ui.item.sortable.dropindex = getItemIndex(ui);
                            var droptarget = ui.item.parent();
                            ui.item.sortable.droptarget = droptarget;

                            var droptargetScope = getElementScope(ui.item.sortable._connectedSortables, droptarget);
                            ui.item.sortable.droptargetModel = droptargetScope.ngModel;

                            // Cancel the sort (let ng-repeat do the sort for us)
                            // Don't cancel if this is the received list because it has
                            // already been canceled in the other list, and trying to cancel
                            // here will mess up the DOM.
                            element.sortable('cancel');
                        }

                        // Put the nodes back exactly the way they started (this is very
                        // important because ng-repeat uses comment elements to delineate
                        // the start and stop of repeat sections and sortable doesn't
                        // respect their order (even if we cancel, the order of the
                        // comments are still messed up).
                        var sortingHelper = !ui.item.sortable.received && getSortingHelper(element, ui, savedNodes);
                        if (sortingHelper && sortingHelper.length) {
                            // Restore all the savedNodes except from the sorting helper element.
                            // That way it will be garbage collected.
                            savedNodes = savedNodes.not(sortingHelper);
                        }
                        savedNodes.appendTo(element);

                        // If this is the target connected list then
                        // it's safe to clear the restored nodes since:
                        // update is currently running and
                        // stop is not called for the target list.
                        if (ui.item.sortable.received) {
                            savedNodes = null;
                        }

                        // If received is true (an item was dropped in from another list)
                        // then we add the new item to this list otherwise wait until the
                        // stop event where we will know if it was a sort or item was
                        // moved here from another list
                        if (ui.item.sortable.received && !ui.item.sortable.isCanceled()) {
                            scope.$apply(function () {
                                ngModel.$modelValue.splice(ui.item.sortable.dropindex, 0,
                                                           ui.item.sortable.moved);
                            });
                        }
                    };

                    callbacks.stop = function (e, ui) {
                        // If the received flag hasn't be set on the item, this is a
                        // normal sort, if dropindex is set, the item was moved, so move
                        // the items in the list.
                        if (!ui.item.sortable.received &&
                           ('dropindex' in ui.item.sortable) &&
                           !ui.item.sortable.isCanceled()) {

                            scope.$apply(function () {
                                ngModel.$modelValue.splice(
                                  ui.item.sortable.dropindex, 0,
                                  ngModel.$modelValue.splice(ui.item.sortable.index, 1)[0]);
                            });
                        } else {
                            // if the item was not moved, then restore the elements
                            // so that the ngRepeat's comment are correct.
                            if ((!('dropindex' in ui.item.sortable) || ui.item.sortable.isCanceled()) &&
                                !angular.equals(element.contents(), savedNodes)) {

                                var sortingHelper = getSortingHelper(element, ui, savedNodes);
                                if (sortingHelper && sortingHelper.length) {
                                    // Restore all the savedNodes except from the sorting helper element.
                                    // That way it will be garbage collected.
                                    savedNodes = savedNodes.not(sortingHelper);
                                }
                                savedNodes.appendTo(element);
                            }
                        }

                        // It's now safe to clear the savedNodes
                        // since stop is the last callback.
                        savedNodes = null;
                    };

                    callbacks.receive = function (e, ui) {
                        // An item was dropped here from another list, set a flag on the
                        // item.
                        ui.item.sortable.received = true;
                    };

                    callbacks.remove = function (e, ui) {
                        // Workaround for a problem observed in nested connected lists.
                        // There should be an 'update' event before 'remove' when moving
                        // elements. If the event did not fire, cancel sorting.
                        if (!('dropindex' in ui.item.sortable)) {
                            element.sortable('cancel');
                            ui.item.sortable.cancel();
                        }

                        // Remove the item from this list's model and copy data into item,
                        // so the next list can retrive it
                        if (!ui.item.sortable.isCanceled()) {
                            scope.$apply(function () {
                                ui.item.sortable.moved = ngModel.$modelValue.splice(
                                  ui.item.sortable.index, 1)[0];
                            });
                        }
                    };

                    wrappers.helper = function (inner) {
                        if (inner && typeof inner === 'function') {
                            return function (e, item) {
                                var innerResult = inner.apply(this, arguments);
                                item.sortable._isCustomHelperUsed = item !== innerResult;
                                return innerResult;
                            };
                        }
                        return inner;
                    };

                    scope.$watchCollection('uiSortable', function (newVal, oldVal) {
                        // ensure that the jquery-ui-sortable widget instance
                        // is still bound to the directive's element
                        var sortableWidgetInstance = getSortableWidgetInstance(element);
                        if (!!sortableWidgetInstance) {
                            var optsDiff = patchUISortableOptions(newVal, oldVal, sortableWidgetInstance);

                            if (optsDiff) {
                                element.sortable('option', optsDiff);
                            }
                        }
                    }, true);

                    patchUISortableOptions(opts);
                }

                function init() {
                    if (ngModel) {
                        wireUp();
                    } else {
                        $log.info('ui.sortable: ngModel not provided!', element);
                    }

                    // Create sortable
                    element.sortable(opts);
                }

                function initIfEnabled() {
                    if (scope.uiSortable && scope.uiSortable.disabled) {
                        return false;
                    }

                    init();

                    // Stop Watcher
                    initIfEnabled.cancelWatcher();
                    initIfEnabled.cancelWatcher = angular.noop;

                    return true;
                }

                initIfEnabled.cancelWatcher = angular.noop;

                if (!initIfEnabled()) {
                    initIfEnabled.cancelWatcher = scope.$watch('uiSortable.disabled', initIfEnabled);
                }
            }
        };
    }
  ]);;
(function () {
    'use strict';

    /**
     * Set Class When At Top
     */
   // var app = angular.module('app', []);
    angular.module('numbersOnly', []).directive('numbersOnly', function () {
       return {
           require: 'ngModel',
           link: function (scope, element, attr, ngModelCtrl) {              
               element.on('keydown', function (event) {
                   var $input = $(this);
                   var value = $input.val();
                   value = value.replace(/[^0-9]/g, '')
                   $input.val(value);
                   if (event.which == 64 || event.which == 16) {
                       // to allow numbers  
                       return false;
                   } else if (event.which >= 48 && event.which <= 57) {
                       // to allow numbers  
                       return true;
                   } else if (event.which >= 96 && event.which <= 105) {
                       // to allow numpad number  
                       return true;
                   } else if ([8, 13, 27, 37, 38, 39, 40].indexOf(event.which) > -1) {
                       // to allow backspace, enter, escape, arrows  
                       return true;
                   } else {
                       event.preventDefault();
                       // to stop others  
                       //alert("Sorry Only Numbers Allowed");  
                       return false;
                   } 
               });
               //ngModelCtrl.$parsers.push(fromUser);
           }
       };
   });
}());;
/**
 * @ngDoc directive
 * @name ng.directive:paging
 *
 * @description
 * A directive to aid in paging large datasets
 * while requiring a small amount of page
 * information.
 *
 * @element EA
 *
 */
angular.module('bw.paging', []).directive('paging', function () {


    /**
     * The regex expression to use for any replace methods
     * Feel free to tweak / fork values for your application
     */
    var regex = /\{page\}/g;


    /**
     * The angular return value required for the directive
     * Feel free to tweak / fork values for your application
     */
    return {

        // Restrict to elements and attributes
        restrict: 'EA',

        // Assign the angular link function
        link: fieldLink,

        // Assign the angular directive template HTML
        template: fieldTemplate,

        // Assign the angular scope attribute formatting
        scope: {
            page: '=?page',
            pageSize: '=?pageSize',
            total: '=?total',
            totalRecord: '=?totalRecord',
            disabled: '@',
            dots: '@',
            ulClass: '@',
            activeClass: '@',
            disabledClass: '@',
            adjacent: '@',
            pagingAction: '&',
            pgHref: '@',
            textFirst: '@',
            textLast: '@',
            textNext: '@',
            textPrev: '@',
            textFirstClass: '@',
            textLastClass: '@',
            textNextClass: '@',
            textPrevClass: '@',
            textTitlePage: '@',
            textTitleFirst: '@',
            textTitleLast: '@',
            textTitleNext: '@',
            textTitlePrev: '@'
        }

    };


    /**
     * Link the directive to enable our scope watch values
     *
     * @param {object} scope - Angular link scope
     * @param {object} el - Angular link element
     * @param {object} attrs - Angular link attribute
     */
    function fieldLink(scope, el, attrs) {

        // Hook in our watched items
        scope.$watchCollection('[page,pageSize,total,disabled,totalRecord]', function () {
            build(scope, attrs);
        });
    }


    /**
     * Create our template html 
     * We use a function to figure out how to handle href correctly
     * 
     * @param {object} el - Angular link element
     * @param {object} attrs - Angular link attribute
     */
    function fieldTemplate(el, attrs) {
        return '<div class="col-lg-12">' +
            '<ul data-ng-hide="Hide" data-ng-class="ulClass" class="margin-left-lg"> ' +
            '<li ' +
                'title="{{Item.title}}" ' +
                'data-ng-class="Item.liClass" ' +
                'data-ng-repeat="Item in List"> ' +
                    '<a ' +
                        (attrs.pgHref ? 'data-ng-href="{{Item.pgHref}}" ' : 'href ') +
                        'data-ng-class="Item.aClass" ' +
                        'data-ng-click="Item.action()" ' +
                        'data-ng-bind="Item.value" class="btn btn-default btn-sm">' +
                    '</a> ' +
            '</li>' +

        '</ul>' +
            '</div>'
    }


    /**
     * Assign default scope values from settings
     * Feel free to tweak / fork these for your application
     *
     * @param {Object} scope - The local directive scope object
     * @param {Object} attrs - The local directive attribute object
     */
    function setScopeValues(scope, attrs) {

        scope.List = [];
        scope.Hide = false;
        if (scope.List != undefined && scope.List != null && scope.List.length > 0) {
            scope.currentPage = scope.List[0].currentPage;
        }

        scope.page = parseInt(scope.page) || 1;
        scope.total = parseInt(scope.total) || 0;
        scope.totalRecord = parseInt(scope.totalRecord) || 0;
        scope.adjacent = parseInt(scope.adjacent) || 1;

        scope.pgHref = scope.pgHref || '';
        scope.dots = scope.dots || '...';

        scope.ulClass = scope.ulClass || 'pagination';
        scope.activeClass = scope.activeClass || 'active';
        scope.disabledClass = scope.disabledClass || 'disabled';

        scope.textFirst = scope.textFirst || 'First';
        scope.textLast = scope.textLast || 'Last';
        scope.textNext = scope.textNext || 'Next';
        scope.textPrev = scope.textPrev || 'Prev';

        scope.textFirstClass = scope.textFirstClass || '';
        scope.textLastClass = scope.textLastClass || '';
        scope.textNextClass = scope.textNextClass || '';
        scope.textPrevClass = scope.textPrevClass || '';

        scope.textTitlePage = scope.textTitlePage || 'Page {page}';
        scope.textTitleFirst = scope.textTitleFirst || 'First Page';
        scope.textTitleLast = scope.textTitleLast || 'Last Page';
        scope.textTitleNext = scope.textTitleNext || 'Next Page';
        scope.textTitlePrev = scope.textTitlePrev || 'Previous Page';

        scope.hideIfEmpty = evalBoolAttribute(scope, attrs.hideIfEmpty);
        scope.showPrevNext = evalBoolAttribute(scope, attrs.showPrevNext);
        scope.showFirstLast = evalBoolAttribute(scope, attrs.showFirstLast);
        scope.scrollTop = evalBoolAttribute(scope, attrs.scrollTop);
        scope.isDisabled = evalBoolAttribute(scope, attrs.disabled);
    }


    /**
     * A helper to perform our boolean eval on attributes
     * This allows flexibility in the attribute for strings and variables in scope
     * 
     * @param {Object} scope - The local directive scope object
     * @param {Object} value - The attribute value of interest
     */
    function evalBoolAttribute(scope, value) {
        return angular.isDefined(value)
            ? !!scope.$parent.$eval(value)
            : false;
    }


    /**
     * Validate and clean up any scope values
     * This happens after we have set the scope values
     *
     * @param {Object} scope - The local directive scope object
     * @param {int} pageCount - The last page number or total page count
     */
    function validateScopeValues(scope, pageCount) {

        // Block where the page is larger than the pageCount
        if (scope.page > pageCount) {
            scope.page = pageCount;
        }

        // Block where the page is less than 0
        if (scope.page <= 0) {
            scope.page = 1;
        }

        // Block where adjacent value is 0 or below
        if (scope.adjacent <= 0) {
            scope.adjacent = 2;
        }

        // Hide from page if we have 1 or less pages
        // if directed to hide empty
        if (pageCount <= 1) {
            scope.Hide = scope.hideIfEmpty;
        }
    }


    /**
     * Assign the method action to take when a page is clicked
     *
     * @param {Object} scope - The local directive scope object
     * @param {int} page - The current page of interest
     */
    function internalAction(scope, page) {

        // Block clicks we try to load the active page
        if (scope.page == page) {
            return;
        }

        // Block if we are forcing disabled 
        if (scope.isDisabled) {
            return;
        }

        // Update the page in scope
        scope.page = page;

        // Pass our parameters to the paging action
        scope.pagingAction({
            page: scope.page,
            pageSize: scope.pageSize,
            total: scope.total,
            totalRecord: scope.totalRecord
        });

        // If allowed scroll up to the top of the page
        if (scope.scrollTop) {
            scrollTo(0, 0);
        }
    }


    /**
     * Add the first, previous, next, and last buttons if desired
     * The logic is defined by the mode of interest
     * This method will simply return if the scope.showPrevNext is false
     * This method will simply return if there are no pages to display
     *
     * @param {Object} scope - The local directive scope object
     * @param {int} pageCount - The last page number or total page count
     * @param {string} mode - The mode of interest either prev or last
     */
    function addPrevNext(scope, pageCount, mode) {

        // Ignore if we are not showing
        // or there are no pages to display
        if ((!scope.showPrevNext && !scope.showFirstLast) || pageCount < 1) {
            return;
        }

        // Local variables to help determine logic
        var disabled, alpha, beta;

        // Determine logic based on the mode of interest
        // Calculate the previous / next page and if the click actions are allowed
        if (mode === 'prev') {

            disabled = scope.page - 1 <= 0;
            var prevPage = scope.page - 1 <= 0 ? 1 : scope.page - 1;

            if (scope.showFirstLast == true && disabled == false) {
                alpha = {
                    value: scope.textFirst,
                    title: scope.textTitleFirst,
                    aClass: scope.textFirstClass,
                    page: 1
                };
            }

            if (scope.showPrevNext == true && disabled==false) {
                beta = {
                    value: scope.textPrev,
                    title: scope.textTitlePrev,
                    aClass: scope.textPrevClass,
                    page: prevPage
                };
            }

        } else {

            disabled = scope.page + 1 > pageCount;
            var nextPage = scope.page + 1 >= pageCount ? pageCount : scope.page + 1;

            if (scope.showPrevNext == true && disabled == false) {
                alpha = {
                    value: scope.textNext,
                    title: scope.textTitleNext,
                    aClass: scope.textNextClass,
                    page: nextPage
                };
            }

            if (scope.showFirstLast == true && disabled == false) {
                beta = {
                    value: scope.textLast,
                    title: scope.textTitleLast,
                    aClass: scope.textLastClass,
                    page: pageCount
                };
            }

        }

        // Create the Add Item Function
        var buildItem = function (item, disabled) {
            return {
                title: item.title,
                aClass: item.aClass,
                value: item.aClass ? '' : item.value,
                liClass: disabled ? scope.disabledClass : '',
                pgHref: disabled ? '' : scope.pgHref.replace(regex, item.page),
                action: function () {
                    if (!disabled) {
                        internalAction(scope, item.page);
                    }
                }
            };
        };

        // Force disabled if specified
        if (scope.isDisabled) {
            disabled = true;
        }

        // Add alpha items
        if (alpha) {
            var alphaItem = buildItem(alpha, disabled);
            scope.List.push(alphaItem);
        }

        // Add beta items
        if (beta) {
            var betaItem = buildItem(beta, disabled);
            scope.List.push(betaItem);
        }
    }


    /**
     * Adds a range of numbers to our list
     * The range is dependent on the start and finish parameters
     *
     * @param {int} start - The start of the range to add to the paging list
     * @param {int} finish - The end of the range to add to the paging list
     * @param {Object} scope - The local directive scope object
     */
    function addRange(start, finish, scope) {

        // Add our items where i is the page number
        var i = 0;
        for (i = start; i <= finish; i++) {

            var pgHref = scope.pgHref.replace(regex, i);
            var liClass = scope.page == i ? scope.activeClass : '';

            // Handle items that are affected by disabled
            if (scope.isDisabled) {
                pgHref = '';
                liClass = scope.disabledClass;
            }


            scope.List.push({
                value: i,
                title: scope.textTitlePage.replace(regex, i),
                liClass: liClass,
                pgHref: pgHref,
                action: function () {
                    internalAction(scope, this.value);
                }
            });
        }
    }


    /**
     * Add Dots ie: 1 2 [...] 10 11 12 [...] 56 57
     * This is my favorite function not going to lie
     *
     * @param {Object} scope - The local directive scope object
     */
    function addDots(scope) {
        scope.List.push({
            value: scope.dots,
            liClass: scope.disabledClass
        });
    }


    /**
     * Add the first or beginning items in our paging list
     * We leverage the 'next' parameter to determine if the dots are required
     *
     * @param {Object} scope - The local directive scope object
     * @param {int} next - the next page number in the paging sequence
     */
    function addFirst(scope, next) {

        addRange(1, 1, scope);

        // We ignore dots if the next value is 3
        // ie: 1 2 [...] 3 4 5 becomes just 1 2 3 4 5
        if (next != 2) {
            addDots(scope);
        }
    }


    /**
     * Add the last or end items in our paging list
     * We leverage the 'prev' parameter to determine if the dots are required
     *
     * @param {int} pageCount - The last page number or total page count
     * @param {Object} scope - The local directive scope object
     * @param {int} prev - the previous page number in the paging sequence
     */
    // Add Last Pages
    function addLast(pageCount, scope, prev) {

        // We ignore dots if the previous value is one less that our start range
        // ie: 1 2 3 4 [...] 5 6  becomes just 1 2 3 4 5 6
        if (prev != pageCount - 1) {
            addDots(scope);
        }

        addRange(pageCount, pageCount, scope);
    }



    /**
     * The main build function used to determine the paging logic
     * Feel free to tweak / fork values for your application
     *
     * @param {Object} scope - The local directive scope object
     * @param {Object} attrs - The local directive attribute object
     */
    function build(scope, attrs) {

        // Block divide by 0 and empty page size
        if (!scope.pageSize || scope.pageSize <= 0) {
            scope.pageSize = 1;
        }

        // Determine the last page or total page count
        var pageCount = Math.ceil(scope.total / scope.pageSize);

        // Set the default scope values where needed
        setScopeValues(scope, attrs);

        // Validate the scope values to protect against strange states
        validateScopeValues(scope, pageCount);

        // Create the beginning and end page values
        var start, finish;

        // Calculate the full adjacency value
        var fullAdjacentSize = (scope.adjacent * 2) + 0;


        // Add the Next and Previous buttons to our list
        addPrevNext(scope, pageCount, 'prev');

        // If the page count is less than the full adjacnet size
        // Then we simply display all the pages, Otherwise we calculate the proper paging display
        if (pageCount <= (fullAdjacentSize + 1)) {

            start = 1;
            addRange(start, pageCount, scope);

        } else {

            // Determine if we are showing the beginning of the paging list
            // We know it is the beginning if the page - adjacent is <= 2
            if (scope.page - scope.adjacent <= 2) {

                start = 1;
                finish = 1 + fullAdjacentSize;

                addRange(start, finish, scope);
                addLast(pageCount, scope, finish);
            }

                // Determine if we are showing the middle of the paging list
                // We know we are either in the middle or at the end since the beginning is ruled out above
                // So we simply check if we are not at the end
                // Again 2 is hard coded as we always display two pages after the dots
            else if (scope.page < pageCount - (scope.adjacent + 1)) {

                start = scope.page - scope.adjacent;
                finish = scope.page + scope.adjacent;

                addFirst(scope, start);
                addRange(start, finish, scope);
                addLast(pageCount, scope, finish);
            }

                // If nothing else we conclude we are at the end of the paging list
                // We know this since we have already ruled out the beginning and middle above
            else {

                start = pageCount - fullAdjacentSize;
                finish = pageCount;

                addFirst(scope, start);
                addRange(start, finish, scope);
            }
        }

        // Add the next and last buttons to our paging list
        addPrevNext(scope, pageCount, 'next');
    }

});
;
(function () {
    'use strict';

    window.app.directive('surveyInputField', surveyInputField);
    function surveyInputField($compile) {
        var TEMPLATES = {
            TextInput:
            '<input type="text" class="form-control" ng-model="$parent.ques.selectedOptionValue" />',
            Multiline:
            '<textarea rows="4" cols"60" class="form-control" ng-model="$parent.ques.selectedOptionValue" />',
            RatingScale:
            '<angular-star-rating max="ques.rangeMaxNumber" value="$parent.ques.selectedOptionValue"  hover="true" is-readonly="false"></angular-star-rating>',
            SingleSlider: //http://angular-slider.github.io/angularjs-slider/
            ' <rzslider rz-slider-model="$parent.ques.selectedOptionValue" rz-slider-options="{floor:ques.rangeMinNumber,ceil:ques.rangeMaxNumber}"></rzslider>',
            DoubleSlider:
            ' <rzslider rz-slider-model="$parent.ques.selectedOptionValue" rz-slider-high="ques.rangeMaxNumber" rz-slider-options="{floor:ques.rangeMinNumber,ceil:ques.rangeMaxNumber}"></rzslider>',
            AsDropdown:
            '    <select' +
            '        name="{{ques.recordId}}"' +
            '        ng-model="$parent.ques.selectedOptionValue"' +
            '        class="form-control wizard"' +
            '        >' +
            '        <option ng-repeat="option in ques.inputOptions"  value="{{option.optionValue}}">{{option.optionText}}</option>' +
            '    </select>',
            AsText:
            '   <div class="col-sm-3" ng-repeat="option in ques.inputOptions track by $index">' +
            '       <div class="col-sm-12 col-xs-12 survey-options" ng-show="$parent.$parent.ques.inputDataType == \'OptionsSingleSelect\'">' +
            '           <div class="control-group">' +
            '               <label class="control control--radio">' +
            '                   <span class="label-survey">{{option.optionText}}</span>' +
            '                   <input type="radio" ng-value="option.optionValue" ng-click="option.stopAddToBag==true?$parent.$parent.ques.showHelpText=true:$parent.$parent.ques.showHelpText=false; $parent.$parent.ques.selectedOptionValue=option.optionValue;" name="singleSelect{{$parent.$parent.ques.recordId}}" ng-class="{\'btn btn-selected\':option.selected, \'btn\':!option.selected}">' +
            '                   <div class="control__indicator"></div>' +
            '               </label>' +
            '           </div>' +
            '       </div>' +
            '   </div>' +
            '    <ul class="pull-left">' +
            '        <li class="options-as-text " ng-repeat="option in ques.inputOptions track by $index">' +
            '            <button class="animate btn-default" ng-show="$parent.$parent.ques.inputDataType == \'OptionsMultipleSelect\'" ng-click="option.selected=!option.selected;$parent.$parent.ques.inputOptions[$index].selectedOptionValue = option.selected;$parent.$parent.ques.selectedOptionValue=option.optionValue" ng-class="{\'animate btn-success\':option.selected, \'animate btn-default\':!option.selected}">' +
            '            <span ng-class="{\'fa\':true, \'fa-check\':option.selected, \'fa-times\':!option.selected}"></span>' +
            '           {{option.optionText}}</button>' +
            '       </li>' +
            '    </ul>',
            AsImage:
            '    <ul>' +
            '        <li class="wizardImg-container" ng-repeat="option in ques.inputOptions track by $index" ng-click="option.selected=!option.selected; $parent.$parent.ques.inputOptions[$index].selectedOptionValue = option.selected;$parent.$parent.ques.selectedOptionValue=option.optionValue">' +
            '            <span ng-class="{\'wizardImg-label-selected\':option.selected}"><i ng-class="{\'fa fa-check\':option.selected, \'fa\':!option.selected}"></i> &nbsp; {{ option.optionText }} </span>' +
            '           <img ng-src="{{$parent.$parent.pm.model.imageBaseUrl}}{{option.imageUrl}}" alt="{{option.optionText}}" />' +
            '           <div class="wizadImg-inputs"> ' +
            '              <input ng-show="ques.inputDataType == \'OptionsMultiSelect\'" type="checkbox" value="option.optionValue" ng-model="$parent.$parent.ques.inputOptions[$index].selectedOptionValue" />' +
            '              <input ng-show="ques.inputDataType == \'OptionsSingleSelect\'" type="radio" value="option.optionValue" ng-model="$parent.$parent.ques.inputOptions[$index].selectedOptionValue" />' +
            '           </div>' +
            '        </li>' +
            '    </ul>',
            AsCarousel:
            '    <ul>' +
            '        <li class="options-as-text " ng-repeat="option in ques.inputOptions track by $index" ng-click="option.selected=!option.selected; $parent.$parent.ques.inputOptions[$index].selectedOptionValue = option.selected;$parent.$parent.ques.selectedOptionValue=option.optionValue">' +
            '            {{option.optionText}} ' +
            '           <img ng-src="{{option.imageUrl}}" alt="{{option.optionText}}" />' +
            '           <div> ' +
            '              <input ng-show="ques.inputDataType === \'OptionsMultiSelect\'" type="checkbox" value="option.optionValue" ng-model="$parent.ques.selectedOptionValue" />' +
            '              <input ng-show="ques.inputDataType === \'OptionsSingleSelect\'" type="radio" value="option.optionValue" ng-model="$parent.ques.selectedOptionValue" />' +
            '           </div>' +
            '        </li>' +
            '    </ul>',
        };

        return {
            restrict: 'E',
            scope: {
                question: "@question"
            },
            link: function (scope, element, attrs) {
                scope.ques = eval("(" + scope.question + ")");
                var tmpl = TEMPLATES[scope.ques.inputStyle];
                element.html(tmpl);

                $compile(element.contents())(scope);
            }
        }
    }
})();
;
window.app.filter('ocxDateTime', function ($filter) {
    var angularDateFilter = $filter('date');
    return function (theDate) {
        return angularDateFilter(theDate, 'dd-MMM-yy @ HH:mm');
    }
});
window.app.filter('ocxTime', function ($filter) {
    var angularDateFilter = $filter('date');
    return function (theDate) {
        return angularDateFilter(theDate, 'HH:mm:ss');
    }
});
window.app.filter('ocxDate', function ($filter) {
    var angularDateFilter = $filter('date');
    return function (theDate) {
        return angularDateFilter(theDate, 'dd-MMM-yy');
    }
});
window.app.filter('ocxMonth', function ($filter) {
    var angularDateFilter = $filter('date');
    return function (theDate) {
        return angularDateFilter(theDate, 'MMM');
    }
});;
angular
  .module('ordinal', [])
  .factory('ordinalService', function () {
    var ordinal = function (input) {
      var n = input % 100;
      return n === 0 ? 'th' : (n < 11 || n > 13) ?
        ['st', 'nd', 'rd', 'th'][Math.min((n - 1) % 10, 3)] : 'th';
    };
    return {
      ordinal: ordinal
    };
  })
  .filter('ordinal', ['ordinalService', function (ordinalService) {
    return function (input) {
      return input + ordinalService.ordinal(input);
    };
  }])
  .filter('ordinalOnly', ['ordinalService', function (ordinalService) {
    return function (input) {
      return ordinalService.ordinal(input);
    };
  }]);;
(function () {
    'use strict';

    window.app.constant('REGEX_CONSTANTS', {
        'LETTERS_AND_NUMBERS_ONLY': '^[a-zA-Z0-9 ]+$',
    });
})();;

(function () {
    'use strict';
    /* Service: AlertService
     * generates the bootstrap alerts for displaying messages that time out.
     */
    window.app.factory('alerts', function ($http, $q, BASE_URL) {
        var isRunning = false;
        var alertContainer = $(".alert-container");
        function showAlert(alert) {
            var template = "<div id='remove' class='alert " + alert.alertClass + "  alert-dismissable'>" + "<i class='fa fa-" + alert.alerticonClass + "'" + "></i>" + alert.message + "</div>";
            var alertElement = template;
            if (isRunning == false) {
                alertContainer.append(alertElement);
                isRunning = true;
            }
            window.setTimeout(function () {
                isRunning = false;
                $("." + alert.alertClass).fadeOut(function () { $(this).remove(); });
            }, 10000);
        }
        function success(message) {
            showAlert({ alertClass: "alert-success", message: message, alerticonClass: "check" });
        }

        function info(message) {
            showAlert({ alertClass: "alert-info", message: message, alerticonClass: "info-sign" });
        }

        function warning(message) {
            showAlert({ alertClass: "alert-warning", message: message, alerticonClass: "exclamation-triangle" });
        }

        function error(message) {
            showAlert({ alertClass: "alert-danger", message: message, alerticonClass: "shield" });
        }

        return {
            showAlert: showAlert,
            success: success,
            info: info,
            warning: warning,
            error: error
        };
    });
}());;
var app = angular.module('CapturePlus', []);
app.directive('capturePlus', function () {
    return {
        require: 'ngModel',
        restrict: 'A',
        link: function (scope, elem, attrs) {
            if (navigator.appName == 'Microsoft Internet Explorer') {
                elem[0].attachEvent('onchange', function () {
                    scope.$apply(function () {
                        var model = attrs.ngModel;
                        scope[model] = elem.val();
                    })
                });
            }
            else {
                elem.bind('change', function () {
                    scope.$apply(function () {
                        var model = attrs.ngModel;
                        scope[model] = elem.val();
                    })
                });
            }
        }
    }

});

app.factory('CapturePlus', function () {
    var capture = {
        CapturePlusCallback: function () { },
        CapturePlusError: function () { },
        CapturePlusStartTyping: function () { }
    }
    window.CapturePlusCallback = function (uid, response) {
        var captureFields = getAllElementsWithAttribute('capture-plus');
        for (var i = 0; i < captureFields.length; i++) {
            var field = document.getElementById(captureFields[i].id);
            if ("fireEvent" in field)
                field.fireEvent("onchange");
            else {
                var evt = document.createEvent("HTMLEvents");
                evt.initEvent("change", false, true);
                field.dispatchEvent(evt);
            }
        }
        capture.CapturePlusCallback(uid, response);
    }
    window.CapturePlusStartTyping = function (uid, response) {
        capture.CapturePlusStartTyping(uid, response);
    }
    window.CapturePlusError = function (uid, response) {
        capture.CapturePlusError(uid, response);
    }
    return capture;
});

function getAllElementsWithAttribute(attribute) {
    var matchingElements = [];
    var allElements = document.getElementsByTagName('*');
    for (var i = 0; i < allElements.length; i++) {
        if (allElements[i].attributes) {
            if (allElements[i].attributes[attribute]) {
                matchingElements.push(allElements[i]);
            }
        }
    }
    return matchingElements;
}
;
//Validation Json
function isJSON(str) {
    try {
        return (JSON.parse(str) && !!str);
    } catch (e) {
        return false;
    }
}
//Validation use only for digit
function isNumberValidate(evt) {
    var theEvent = evt || window.event;
    var key = theEvent.keyCode || theEvent.which;
    key = String.fromCharCode(key);
    var regex = /[0-9]|\./;
    if (!regex.test(key)) {
        theEvent.returnValue = false;
        if (theEvent.preventDefault) theEvent.preventDefault();
    }
}

function validatePostCode(postCode, countryCode) {
    var country = '';
    //var country = regxGlobalPostCodes.find(x => x.ISO === countryCode);
    angular.forEach(regxGlobalPostCodes, function (pCode) {
        if (pCode.ISO === countryCode) {
            country = pCode;
        }
    });
    if (country != undefined && country != null) {
        var regex = new RegExp(country.Regex);
        return regex.test(postCode);
    }
    return false;
}
/* This function is included as JS SDK for IE does not contains URLSearchParams and related function.
   Need to add this in Core JS modules for re-usability.
*/
 function GetUrlSearchParams(name) {
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results == null) {
        return null;
    }
    else {
        return decodeURI(results[1]) || null;
    }
};
var regxGlobalPostCodes= [
   {
     "Note": "Known as the postcode. The first letter(s) indicate the postal area, such as the town or part of London. Placed on a separate line below the city (or county, if used). The UK postcode is made up of two parts separated by a space. These are known as the outward postcode and the inward postcode. The outward postcode is always one of the following formats: AN, ANN, AAN, AANN, ANA, AANA, AAA. The inward postcode is always formatted as NAA. A valid inward postcode never contains the letters: C, I, K, M, O or V. The British Forces Post Office has a different system, but as of 2012 has also adopted UK-style postcodes that begin with \"BF1\" for electronic compatibility.",
     "Country": "United Kingdom",
     "ISO": "GB",
     "Format": "A(A)N(A/N)NAA (A[A]N[A/N] NAA)",
     "Regex": "[A-Z]{1,2}[0-9R][0-9A-Z]? (?:(?![CIKMOV])[0-9][a-zA-Z]{2})"
   }
];
/*

Quicksand 1.2.2

Reorder and filter items with a nice shuffling animation.

Copyright (c) 2010 Jacek Galanciak (razorjack.net) and agilope.com
Big thanks for Piotr Petrus (riddle.pl) for deep code review and wonderful docs & demos.

Dual licensed under the MIT and GPL version 2 licenses.
http://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt
http://github.com/jquery/jquery/blob/master/GPL-LICENSE.txt

Project site: http://razorjack.net/quicksand
Github site: http://github.com/razorjack/quicksand

*/

(function ($) {
    $.fn.quicksand = function (collection, customOptions) {     
        var options = {
            duration: 750,
            easing: 'swing',
            attribute: 'data-id', // attribute to recognize same items within source and dest
            adjustHeight: 'auto', // 'dynamic' animates height during shuffling (slow), 'auto' adjusts it before or after the animation, false leaves height constant
            useScaling: true, // disable it if you're not using scaling effect or want to improve performance
            enhancement: function(c) {}, // Visual enhacement (eg. font replacement) function for cloned elements
            selector: '> *',
            dx: 0,
            dy: 0
        };
        $.extend(options, customOptions);
        
        //if ($.browser.msie || (typeof($.fn.scale) == 'undefined')) {
        //    // Got IE and want scaling effect? Kiss my ass.
        //    options.useScaling = false;
        //}
        
        var callbackFunction;
        if (typeof(arguments[1]) == 'function') {
            var callbackFunction = arguments[1];
        } else if (typeof(arguments[2] == 'function')) {
            var callbackFunction = arguments[2];
        }
    
        
        return this.each(function (i) {
            var val;
            var animationQueue = []; // used to store all the animation params before starting the animation; solves initial animation slowdowns
            var $collection = $(collection).clone(); // destination (target) collection
            var $sourceParent = $(this); // source, the visible container of source collection
            var sourceHeight = $(this).css('height'); // used to keep height and document flow during the animation
            
            var destHeight;
            var adjustHeightOnCallback = false;
            
            var offset = $($sourceParent).offset(); // offset of visible container, used in animation calculations
            var offsets = []; // coordinates of every source collection item            
            
            var $source = $(this).find(options.selector); // source collection items
            
            // Replace the collection and quit if IE6
            //if ($.browser.msie && $.browser.version.substr(0,1)<7) {
            //    $sourceParent.html('').append($collection);
            //    return;
            //}

            // Gets called when any animation is finished
            var postCallbackPerformed = 0; // prevents the function from being called more than one time
            var postCallback = function () {
                
                if (!postCallbackPerformed) {
                    postCallbackPerformed = 1;
                    
                    // hack: 
                    // used to be: $sourceParent.html($dest.html()); // put target HTML into visible source container
                    // but new webkit builds cause flickering when replacing the collections
                    $toDelete = $sourceParent.find('> *');
                    $sourceParent.prepend($dest.find('> *'));
                    $toDelete.remove();
                         
                    if (adjustHeightOnCallback) {
                        $sourceParent.css('height', destHeight);
                    }
                    options.enhancement($sourceParent); // Perform custom visual enhancements on a newly replaced collection
                    if (typeof callbackFunction == 'function') {
                        callbackFunction.call(this);
                    }                    
                }
            };
            
            // Position: relative situations
            var $correctionParent = $sourceParent.offsetParent();
            var correctionOffset = $correctionParent.offset();
            if ($correctionParent.css('position') == 'relative') {
                if ($correctionParent.get(0).nodeName.toLowerCase() == 'body') {

                } else {
                    correctionOffset.top += (parseFloat($correctionParent.css('border-top-width')) || 0);
                    correctionOffset.left +=( parseFloat($correctionParent.css('border-left-width')) || 0);
                }
            } else {
                correctionOffset.top -= (parseFloat($correctionParent.css('border-top-width')) || 0);
                correctionOffset.left -= (parseFloat($correctionParent.css('border-left-width')) || 0);
                correctionOffset.top -= (parseFloat($correctionParent.css('margin-top')) || 0);
                correctionOffset.left -= (parseFloat($correctionParent.css('margin-left')) || 0);
            }
            
            // perform custom corrections from options (use when Quicksand fails to detect proper correction)
            if (isNaN(correctionOffset.left)) {
                correctionOffset.left = 0;
            }
            if (isNaN(correctionOffset.top)) {
                correctionOffset.top = 0;
            }
            
            correctionOffset.left -= options.dx;
            correctionOffset.top -= options.dy;

            // keeps nodes after source container, holding their position
            $sourceParent.css('height', $(this).height());
            
            // get positions of source collections
            $source.each(function (i) {
                offsets[i] = $(this).offset();
            });
            
            // stops previous animations on source container
            $(this).stop();
            var dx = 0; var dy = 0;
            $source.each(function (i) {
                $(this).stop(); // stop animation of collection items
                var rawObj = $(this).get(0);
                if (rawObj.style.position == 'absolute') {
                    dx = -options.dx;
                    dy = -options.dy;
                } else {
                    dx = options.dx;
                    dy = options.dy;                    
                }

                rawObj.style.position = 'absolute';
                rawObj.style.margin = '0';

                rawObj.style.top = (offsets[i].top - parseFloat(rawObj.style.marginTop) - correctionOffset.top + dy) + 'px';
                rawObj.style.left = (offsets[i].left - parseFloat(rawObj.style.marginLeft) - correctionOffset.left + dx) + 'px';
            });
                    
            // create temporary container with destination collection
            var $dest = $($sourceParent).clone();
            var rawDest = $dest.get(0);
            rawDest.innerHTML = '';
            rawDest.setAttribute('id', '');
            rawDest.style.height = 'auto';
            rawDest.style.width = $sourceParent.width() + 'px';
            $dest.append($collection);      
            // insert node into HTML
            // Note that the node is under visible source container in the exactly same position
            // The browser render all the items without showing them (opacity: 0.0)
            // No offset calculations are needed, the browser just extracts position from underlayered destination items
            // and sets animation to destination positions.
            $dest.insertBefore($sourceParent);
            $dest.css('opacity', 0.0);
            rawDest.style.zIndex = -1;
            
            rawDest.style.margin = '0';
            rawDest.style.position = 'absolute';
            rawDest.style.top = offset.top - correctionOffset.top + 'px';
            rawDest.style.left = offset.left - correctionOffset.left + 'px';
            
            
    
            

            if (options.adjustHeight === 'dynamic') {
                // If destination container has different height than source container
                // the height can be animated, adjusting it to destination height
                var heigh=$dest.height()/6;
                $sourceParent.animate({height:heigh }, options.duration, options.easing);
            } else if (options.adjustHeight === 'auto') {
                destHeight = $dest.height();
                if (parseFloat(sourceHeight) < parseFloat(destHeight)) {
                    // Adjust the height now so that the items don't move out of the container
                    $sourceParent.css('height', destHeight);
                } else {
                    //  Adjust later, on callback
                    adjustHeightOnCallback = true;
                }
            }
                
            // Now it's time to do shuffling animation
            // First of all, we need to identify same elements within source and destination collections    
            $source.each(function (i) {
                var destElement = [];
                if (typeof(options.attribute) == 'function') {
                    
                    val = options.attribute($(this));
                    $collection.each(function() {
                        if (options.attribute(this) == val) {
                            destElement = $(this);
                            return false;
                        }
                    });
                } else {
                    destElement = $collection.filter('[' + options.attribute + '=' + $(this).attr(options.attribute) + ']');
                }
                if (destElement.length) {
                    // The item is both in source and destination collections
                    // It it's under different position, let's move it
                    if (!options.useScaling) {
                        animationQueue.push(
                                            {
                                                element: $(this), 
                                                animation: 
                                                    {top: destElement.offset().top - correctionOffset.top, 
                                                     left: destElement.offset().left - correctionOffset.left, 
                                                     opacity: 1.0
                                                    }
                                            });

                    } else {
                        animationQueue.push({
                                            element: $(this), 
                                            animation: {top: destElement.offset().top - correctionOffset.top, 
                                                        left: destElement.offset().left - correctionOffset.left, 
                                                        opacity: 1.0, 
                                                        scale: '1.0'
                                                       }
                                            });

                    }
                } else {
                    // The item from source collection is not present in destination collections
                    // Let's remove it
                    if (!options.useScaling) {
                        animationQueue.push({element: $(this), 
                                             animation: {opacity: '0.0'}});
                    } else {
                        animationQueue.push({element: $(this), animation: {opacity: '0.0', 
                                         scale: '0.0'}});
                    }
                }
            });
            
            $collection.each(function (i) {
                // Grab all items from target collection not present in visible source collection
                
                var sourceElement = [];
                var destElement = [];
                if (typeof(options.attribute) == 'function') {
                    val = options.attribute($(this));
                    $source.each(function() {
                        if (options.attribute(this) == val) {
                            sourceElement = $(this);
                            return false;
                        }
                    });                 

                    $collection.each(function() {
                        if (options.attribute(this) == val) {
                            destElement = $(this);
                            return false;
                        }
                    });
                } else {
                    sourceElement = $source.filter('[' + options.attribute + '=' + $(this).attr(options.attribute) + ']');
                    destElement = $collection.filter('[' + options.attribute + '=' + $(this).attr(options.attribute) + ']');
                }
                
                var animationOptions;
                if (sourceElement.length === 0) {
                    // No such element in source collection...
                    if (!options.useScaling) {
                        animationOptions = {
                            opacity: '1.0'
                        };
                    } else {
                        animationOptions = {
                            opacity: '1.0',
                            scale: '1.0'
                        };
                    }
                    // Let's create it
                    d = destElement.clone();
                    var rawDestElement = d.get(0);
                    rawDestElement.style.position = 'absolute';
                    rawDestElement.style.margin = '0';
                    rawDestElement.style.top = destElement.offset().top - correctionOffset.top + 'px';
                    rawDestElement.style.left = destElement.offset().left - correctionOffset.left + 'px';
                    d.css('opacity', 0.0); // IE
                    if (options.useScaling) {
                        d.css('transform', 'scale(0.0)');
                    }
                    d.appendTo($sourceParent);
                    
                    animationQueue.push({element: $(d), 
                                         animation: animationOptions});
                }
            });
            
            $dest.remove();
            options.enhancement($sourceParent); // Perform custom visual enhancements during the animation
            for (i = 0; i < animationQueue.length; i++) {
                animationQueue[i].element.animate(animationQueue[i].animation, options.duration, options.easing, postCallback);
            }
        });
    };
})(jQuery);;
(function () {
    'use strict';
    window.app.factory('loader', ['$http', '$rootScope', function ($http, $rootScope) {

        angular.element(document).ready(function () {
            angular.element(".dvloader").hide();
        });

        $http.defaults.transformRequest.push(function (data) {
            angular.element(".dvloader").show();
            return data;
        });
        $http.defaults.transformResponse.push(function (data) {
            angular.element(".dvloader").hide();
            return data;
        })
        return $http;
    }]);
}());
;
function loadPCAScript(scriptLoader, pcaAccessCode) {

    if (pcaAccessCode != undefined && pcaAccessCode != '') {
        scriptLoader.load("//services.postcodeanywhere.co.uk/css/captureplus-2.30.min.css?key=" + pcaAccessCode, "text/css", "stylesheet");
        scriptLoader.load("//services.postcodeanywhere.co.uk/js/captureplus-2.30.min.js?key=" + pcaAccessCode, "text/javascript", "");
    }
}
function setPCALookup(pcaAccessCode, country, address1Id, address2Id, cityId, stateId, postCodeid, companynameid, countryCode, countryId, countryElementId) {
    if (pcaAccessCode != undefined && pcaAccessCode != '') {
        if (!countryCode)
            countryCode= document.getElementById("selectedBillCountry").value;
        if (!countryElementId) {
            countryId = 'selectedBillCountry'
        }
        window.setTimeout(function () {
            // address PCA Predict
            var optionsAddress = {
                key: pcaAccessCode,
                countries: { codeList: countryCode}
            };

            var fieldsAddress = [
                { element: address1Id, field: 'Line1' },
                { element: address2Id, field: 'Line2', mode: pca.fieldMode.POPULATE },
                { element: cityId, field: 'City', mode: pca.fieldMode.POPULATE },
                { element: stateId, field: 'Province', mode: pca.fieldMode.POPULATE },
                { element: postCodeid, field: 'PostalCode' },
                { element: countryElementId, field: 'CountryName', mode: pca.fieldMode.COUNTRY }
            ];

            var controlAddress = new pca.Address(fieldsAddress, optionsAddress);

            controlAddress.listen('options', function (options) {
                options.countries = options.countries || {};
                options.countries.codesList = country;
            });

            controlAddress.listen('populate', function (address, variations) {
                CapturePlusCallback();
            });

            controlAddress.load();
        }, 1500);
    }
}
;
(function () {
    'use strict';
    window.app.factory('scriptLoader', function () {
        return {
            load: function (url, type, rel) {
                if (type === undefined) type = 'text/javascript';
                if (url) {
                    var script = document.querySelector("script[src*='" + url + "']");
                    if (!script) {
                        var heads = document.getElementsByTagName("head");
                        if (heads && heads.length) {
                            var head = heads[0];
                            if (head) {
                                if (!rel) {
                                    script = document.createElement('script');
                                    script.setAttribute('src', url)
                                } else {
                                    script = document.createElement('link');
                                    script.setAttribute('href', url)
                                }
                                script.setAttribute('type', type);
                                if (rel) script.setAttribute('rel', rel);
                                head.appendChild(script);
                            }
                        }
                    }
                    return script;
                }
            }
        };
    });
}());;
(function () {
    'use strict';
    /* Service: AdminData
     * Defines the methods related to global data across the app
     */
    window.app.factory('Recommendation', function ($http, $q, BASE_URL) {       
        var factory = {};
        var RECENT_PRODUCT_COOKIE = '_rvp';
        return {
            getRecommendation: function () {
                var deferred = $q.defer();
                var recentViewedProducts = $.cookie(RECENT_PRODUCT_COOKIE);
                if (recentViewedProducts) {
                    var recentViewedProductList = recentViewedProducts.split(",");
                }
                var pagePath = window.location.pathname;
                $http.post(BASE_URL + '/Recomendation/GetItemRecommendations', { itemId: dataLayer[0].EntityId, recentViewedProductList: recentViewedProductList, pageCategory: dataLayer[0].PageCategory }).success(deferred.resolve).error(deferred.reject);
                return deferred.promise;  
            }
        }
    });
}());;
(function () {
    'use strict';
    // Added constant for Bulk Order Messages
    window.app.constant('BULKORDER_CONSTANTS', {
        'STOCK_UNAVAILABLE': 'QP01',
        'STOCK_AVAILABLE': 'QP02',
        'SUCCESS': 'C001',
        'POSTCODE': 'POSTCODE',
        'ITEM_STOCK_UNAVAILABLE': 'C002',
        'PREORDER_ITEM_STOCK_AVAILABLE': 'C003'
    });
    ;
    window.app.constant("PERSONALISATION", {
        'ENABLED': "PersonalisationEnabled",
        'MANDATORY': 'PersonalisationMandatory'
    });
    window.app.constant("CURRENCYCOOKIE", {
        'CurrencyCode': "_ctcc"
    });
    window.app.constant("VOUCHERSTATUS", {
        'CLAIMED': "Claimed",
        'UNCLAIMED': 'Unclaimed',
        'IN_TRANSITION': 'InTransition',
    });
    window.app.constant("MULTIFILFILLMENT", {
        'URL_POPULATE_DELIVERY_PLANS': "/basket/populate-delivery-plans",
        'URL_FIX_DELIVERY_PLANS': "/basket/fix-delivery-plans",
    });
    window.app.constant("MEMBERSHIP", {
        'URL_UPGRADE_OPTIONS': "/my-tfs-membership/upgrade-options",
        'URL_SIGNUP_OPTIONS': "/my-tfs-membership/signup-options",
        'URL_SIGNUP_ADD': "/Basket/AddMembership",
    });
    // ADD CONSTANT FOR THEME DEFAULT IMAGE
    window.DEFAULT_IMAGE_URL = '/assets/theme/tfs/images/noimagefound.jpg';
    window.app.controller('globalCtrl', globalCtrl);
    globalCtrl.$inject = [
        '$scope',
        '$timeout',
        'globalConfig',
        'loader',
        '$http',
        'CapturePlus',
        'scriptLoader',
        'BULKORDER_CONSTANTS',
        'Recommendation',
        'PERSONALISATION',
        'REGEX_CONSTANTS',
        'alerts',
        'CURRENCYCOOKIE',
        'VOUCHERSTATUS',
        'vcRecaptchaService',
        'MULTIFILFILLMENT',
        'MEMBERSHIP'
    ];

    function globalCtrl(
        $scope,
        $timeout,
        globalConfig,
        $http,
        loader,
        CapturePlus,
        scriptLoader,
        BULKORDER_CONSTANTS,
        Recommendation,
        PERSONALISATION,
        REGEX_CONSTANTS,
        alerts,
        CURRENCYCOOKIE,
        VOUCHERSTATUS,
        vcRecaptchaService,
        MULTIFILFILLMENT,
        MEMBERSHIP
    ) {
        var gm = this;
        gm.model = {};
        $scope.personalisation = /^[a-zA-Z0-9 \n!"£$%^&*(){};:@'#~?/.>,<|_+=`\-\\\[\]]+$/;
        $scope.ribbonPersonalisation = /^[a-zA-Z0-9 ]+$/;

        gm.defaultCurrency = "£";

        gm.errorMessage == null;
        gm.stockErrorMessage == null;
        gm.saving = false;
        gm.success = false;
        gm.basketResponse = null;
        gm.updateQtyAndAdd = updateQtyAndAdd;
        gm.basketExtraInfo = [];
        gm.miniBasketSize = 3;
        gm.lineItemTotal = 0;
        gm.shippingMethods = [];
        gm.maximumBasketItemError = false;
        gm.invalidpromo = false;
        gm.blogReponse = [];
        gm.emailinvalid = false;
        gm.subssuccess = false;
        gm.customerEmail = '';
        gm.alreadySubscribed = false;
        gm.emptyGuid = '00000000-0000-0000-0000-000000000000';
        gm.activeMemebershipPlanId = '00000000-0000-0000-0000-000000000000';
        gm.openQuickBasketModal = openQuickBasketModal;
        gm.nRows = nRows;
        gm.userName = '';
        gm.incVat = ($.cookie('incVat') === undefined) ? false : ($.cookie('incVat') == 'true');
        gm.isChecked = !gm.incVat;
        $scope.signin = false;
        $scope.register = false;
        $scope.global_login = false;
        gm.basketData = null;
        gm.isPasswordPolicyMeet = isPasswordPolicyMeet;
        gm.customError = customError;
        gm.basketContainsMembership = false;
        gm.basketContainsSubscription = false;
        gm.basketContainsVirtual = false;
        gm.checkBasketContainsMembership = checkBasketContainsMembership;
        gm.hasOnlyMembershipProducts = hasOnlyMembershipProducts;
        gm.potentialSavings = 0;
        gm.isShipFromStoreProduct = false;

        //methods
        gm.userLogin = userLogin;
        gm.registration = registration;
        gm.contactForm = contactForm;
        gm.currencySettings = currencySettings;
        gm.initBasket = initBasket;
        gm.showShippingGrid = showShippingGrid;
        gm.addToBasket = addToBasket;
        gm.getPaymentMethods = getPaymentMethods;
        gm.getShippingMethods = getShippingMethods;
        gm.updateShipping = updateShipping;
        gm.applyPromoCode = applyPromoCode;
        gm.getallblogs = getallblogs;
        gm.getallblogsbycategory = getallblogsbycategory;
        gm.getBlogByCategory = getBlogByCategory;
        gm.initblogs = initblogs;
        gm.login = login;
        gm.passwordCheckTimeout1 = null;
        gm.passwordCheckTimeout2 = null;
        gm.globalLogin = globalLogin;
        gm.newsLetterSubscription = newsLetterSubscription;
        gm.showBasket = showBasket;
        gm.removePromoCode = removePromoCode;
        gm.forgotPassword = forgotPassword;
        gm.addProductsExcel = addProductsExcel;
        gm.registerCompanyRequest = registerCompanyRequest;
        gm.productPrice = productPrice;
        gm.socialSignIn = socialSignIn;
        gm.getSocialSettings = getSocialSettings;
        gm.getBillingCountries = getBillingCountries;
        gm.basketDetails = basketDetails;
        gm.hideBasketDetail = hideBasketDetail;
        gm.checkForSpecificAttribute = checkForSpecificAttribute;
        gm.onTextFocus = onTextFocus;
        gm.checkPassword = checkPassword;
        gm.isPasswordValid = false;
        gm.returnUrl = '';
        var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
        var eventer = window[eventMethod];
        var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
        gm.addQuoteToBasket = addQuoteToBasket;
        gm.removeQuoteBasket = removeQuoteBasket;
        gm.basketAction = basketAction;
        gm.cancelChangePostCode = cancelChangePostCode;
        gm.serializedData = serializedData;
        gm.forPaymentUpdate = false;
        gm.formReset = formReset;
        gm.removeProductToWishlist = removeProductToWishlist;
        gm.initLookbooks = initLookbooks;
        gm.addLookbookToCart = addLookbookToCart;
        gm.fetchLookbookByGroup = fetchLookbookByGroup;
        gm.updateBasketQty = updateBasketQty;
        gm.getRecommendations = getRecommendations;
        gm.addSampleLookbookToCart = addSampleLookbookToCart;
        gm.activeClass = '';
        let greetingCardsLoaded = false;

        //login screens
        gm.emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/;
        gm.minPasswordLength = 6;
        gm.maxPasswordLength = 50;
        gm.loginTab = loginTab;
        gm.createAccountTab = createAccountTab;
        gm.signing = false;
        gm.registering = false;
        gm.resettingPassword = false;
        gm.passwordResetSuccess = false;

        //Engraving Section Starts
        gm.applyPersonalisation = applyPersonalisation;
        gm.editPersonalisation = editPersonalisation;
        gm.removePersonalisation = removePersonalisation;
        gm.range = range;
        gm.engravingFailedAction = 'remove';
        gm.engravingProduct = null;
        gm.closeEngravingFailedModal = closeEngravingFailedModal;
        gm.engravingColour = 'WHITE'; //default engraving colour
        gm.engravingRegex = REGEX_CONSTANTS.LETTERS_AND_NUMBERS_ONLY; //default engraving colour
        gm.engravingSubmitInProgress = false;
        //Engraving Section Ends

        //Gift wrapping section 
        gm.selectedGiftWrapOption = {};
        gm.sourceProcess = 'NEWSLETTER';
        gm.selectedLineItem = {};
        gm.isGiftWrapApplied = false;
        gm.giftWrapError = false;
        gm.addGiftButtonClicked = false;
        gm.addGiftWrapSelected = addGiftWrapSelected;
        gm.addGiftWrap = addGiftWrap;
        gm.addPersonalisedRibbon = addPersonalisedRibbon;
        gm.addPersonalisedRibbonForm = addPersonalisedRibbonForm;
        gm.addRibbon = addRibbon;
        gm.updateRibbon = updateRibbon;
        gm.editRibbon = editRibbon;
        gm.removeRibbon = removeRibbon;
        gm.checkGiftWrap = checkGiftWrap;
        gm.removeGiftWrap = removeGiftWrap;
        gm.updateBasketBadgeCount = updateBasketBadgeCount;
        gm.changeBaseCurrency = changeBaseCurrency;
        gm.showEditRibbon = false;
        gm.backGiftWrapModal = backGiftWrapModal;
        gm.closeGiftWrapModal = closeGiftWrapModal;
        gm.selectedRibbonOption = {};
        gm.giftWrapRibbonPrice = giftWrapRibbonPrice;
        gm.basketContainShipFromStoreItems = false;

        //ADDONS
        gm.addonsActionPending = false;

        //Greeting cards section
        gm.selectedGreetingCardOption = {};
        gm.selectedGreetingCard = {};
        gm.isGreetingCardApplied = false;
        gm.selectedCardItem = {};
        gm.addGreetingCard = addGreetingCard;
        gm.addGreetingCardPersonalisation = addGreetingCardPersonalisation;
        $scope.tsCsChecked = false;
        gm.openGreetingCardModal = openGreetingCardModal;
        gm.closeGreetingCardModal = closeGreetingCardModal;
        gm.backGreetingCardModal = backGreetingCardModal;
        gm.editGreetingCard = editGreetingCard;
        gm.hideGreetingCard = hideGreetingCard;
        gm.saveEditGreetingCard = saveEditGreetingCard;
        gm.removeGreetingCard = removeGreetingCard;
        gm.greetingCardOptions = [];
        gm.greetingCardSelected = [];
        gm.greetingCardOption = [];
        gm.addGreetingCardButtonClicked = false;

        /*******below code is for recomendation**********/
        gm.recomendations = {};
        gm.openGiftModal = openGiftModal;
        gm.editGiftModal = editGiftModal;
        gm.saveRibbon = saveRibbon;
        // data used to generate qty dropdown in basket 
        gm.basketQtyDropdown = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

        //subscription block starts
        gm.removeSubscription = removeSubscription;
        gm.unsubscribedNewsletter = unsubscribedNewsletter;

        //This variable is used to show static offer recommendation for beauty[Indulge] and SA segment
        gm.offerCategoryName = "";
        gm.isNewsLetterSubscribed = $.cookie("NewsLetterSubscribed");
        gm.isProductExist = false;
        gm.couponProvider = '';
        gm.showCurrencyPopUp = showCurrencyPopUp;
        gm.memberShipAlert = null;
        gm.setCookie = setCookie;
        gm.initMembershipPlans = initMembershipPlans;
        gm.getUnClaimedVouchers = getUnClaimedVouchers;
        gm.applyMembershipVoucher = applyMembershipVoucher;
        gm.checkVoucherApplied = checkVoucherApplied;
        gm.deletedPromoCode = '';
        gm.membershipVoucherApplied = false;
        //fragrance match
        gm.currentlySelectedProductId = '00000000-0000-0000-0000-000000000000';

        //Multifulfillment
        //NEW TFS properties used to determine if we are showing the modals to the user
        gm.tfsBasketDataValidation = {
            validBasket: true,
            validAddons: true,
            validProducts: true,
            disableGiftWrap: false
        }
        gm.shipFromStoreModalInitial = true;
        gm.apiPendingTfs = false;
        gm.isBasketPage = window.location.pathname.toLowerCase() === '/basket';
        gm.isAccountMembershipPage = window.location.pathname.indexOf('/Account/membership') > -1;
        gm.isMembershipLandingPage = window.location.pathname.indexOf('/my-tfs-membership') > -1;
        gm.proceedToCheckout = proceedToCheckout;
        gm.fixDeliveryPlans = fixDeliveryPlans;

        gm.deliveryPlanApiPending = false;
        gm.checkApisStatus = checkApisPending;
        gm.showBasketWarning = false;
        gm.showMembershipWarning = false;

        //reCAPTCHA
        gm.widgetId = null;
        gm.setWidgetId = setWidgetId;

        //validate membership and membership basket
        gm.validateMembership = validateMembership;
        gm.userHasMembership = 0;
        gm.showMembershipBasketErrorMsg = false;
        gm.applyMembershipVoucherAfterRedirect = false;

        gm.changeBaseCurrencyV2 = changeBaseCurrencyV2;
        gm.enableChangeBaseCurrencyV2 = 0;
        gm.selectedCurrencySymbol = null;

        //subscription block ends
        function removeSubscription() {
            if (gm.subscriptionItems != null && gm.subscriptionItems != undefined && gm.subscriptionItems.length > 0) {
                var model = [];
                angular.forEach(gm.subscriptionItems, function (item) {
                    model.push({
                        basketId: gm.basketResponse.id,
                        productId: item.productId,
                        qty: 0,
                        stockCode: item.stockCode,
                        isSubscription: item.isSubscription
                    });
                });
                $http.post(globalConfig.bulkAddproduct, { model: model }).then(function (success) {
                    updateBasket(success.data);
                    extractSubscription();
                }, function (error) {
                });
            }
        }

        gm.changeSubscriptionBasketDisplayOrder = {
            update: function (e, ui) {
                //perform before sort math. 
            },
            stop: function (e, ui) {
                //perform after sort math. 
                var lines = [];
                angular.forEach(gm.subscriptionItems, function (item, key) {
                    item.displayOrder = key + 1;
                    lines.push({ id: item.id, displayOrder: key + 1 })
                });
                //add other basket items.
                $http.post(globalConfig.updateLineDisplayOrder, {
                    basketId: gm.basketResponse.id,
                    lines: lines
                }).then(function (sucess) {

                }, function (error) {
                });
            }
        }
        //function initPCALookup() {
        //    if (globalConfig.pcaAccessCode != undefined && globalConfig.pcaAccessCode != '') {
        //        window.setTimeout(function () {
        //            if (!gm.defaultCountry) {
        //                $http.post(globalConfig.getDefaultCountryUrl)
        //                    .success(function (country) { gm.defaultCountry = country; });
        //            }
        //            // address PCA Predict
        //            var optionsBilling = {
        //                key: globalConfig.pcaAccessCode,
        //                countries: {
        //                    codeList: gm.defaultCountry
        //                }
        //            };

        //            var fieldsBilling = [
        //                { element: 'gm.model.company.address1', field: 'Line1' },
        //                { element: 'gm.model.company.address2', field: 'Line2', mode: pca.fieldMode.POPULATE },
        //                { element: 'gm.model.company.city', field: 'City', mode: pca.fieldMode.POPULATE },
        //                { element: 'gm.model.company.state', field: 'Province', mode: pca.fieldMode.POPULATE },
        //                { element: 'gm.model.company.postCode', field: 'PostalCode' }
        //            ];

        //            var controlBilling = new pca.Address(fieldsBilling, optionsBilling);

        //            controlBilling.listen('options', function (options) {
        //                options.countries = options.countries || {};
        //                options.countries.codesList = "GB" //document.getElementById('gm.model.countryCode').value;
        //            });

        //            controlBilling.listen('populate', function (address, variations) {
        //                CapturePlusCallback();
        //            });

        //            controlBilling.load();
        //        }, 1500);
        //    }
        //}

        function loginTab() {
            if (!gm.loginAccount && gm.createAccount) {
                gm.errorMessage = null;
                gm.loginAccount = true;
                gm.createAccount = false;
            }
        }

        function createAccountTab() {
            if (gm.loginAccount && !gm.createAccount) {
                gm.errorMessage = null;
                gm.loginAccount = false;
                gm.createAccount = true;
            }
        }


        function checkForSpecificAttribute(attributeCode, attributevalue, item) {
            //search in specific line item
            if (item != null && item != undefined) {
                var attributesJson = JSON.parse(item.attributesJson);
                if (attributesJson.Attributes != null || attributesJson.Attributes != undefined) {
                    for (var i = 0; i < attributesJson.Attributes.length; i++) {
                        if (attributesJson.Attributes[i].FieldCode == attributeCode && attributesJson.Attributes[i].FieldValue == attributevalue) {
                            return true;
                        }
                    }
                }
                return false;
            }//search in all line items
            else {
                var flag = false;
                if (gm.basketResponse.lineItems != null) {
                    angular.forEach(gm.basketResponse.lineItems, function (line) {
                        var parsedJSON = eval('(' + line.attributesJson + ')');
                        var attr = parsedJSON.Attributes;
                        if (attr != null) {
                            for (i = 0; i < attr.length; i++) {
                                // this can be a string or null
                                var FieldCode = attr[i].FieldCode;
                                var FieldValue = attr[i].FieldValue;
                                if (FieldCode != null && FieldCode != "" && FieldCode == attributeCode) {
                                    //line.customInfo1 = FieldCode + "" + FieldValue;
                                    if (FieldValue != null && FieldValue == attributevalue) {
                                        flag = true;
                                        break;
                                    }
                                }
                            }
                        }
                        if (flag)
                            return flag;
                    });
                    return flag;
                }
            }
        }


        function contactForm(model) {
            $(".alertBlock").fadeIn();
            $http.post(globalConfig.setContactForm, { model: model })
                .success(function (data) {
                    if (!data.isValid != null && typeof data.errorMessages != 'undefined' && data.errorMessages.length > 0) {
                        gm.errorMessage = data.errorMessages;
                        $timeout(function () {
                            $(".alertBlock").fadeOut();
                        }, 10000);
                        return;
                    }
                    gm.errorMessage = null;
                    gm.success = true;
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    gm.saving = false;
                    $timeout(function () {
                        $(".alertBlock").fadeOut();
                    }, 10000);
                });
        }

        //#region Basket
        function applyPromoCode(basketId, promoCode) {
            gm.apiPendingTfs = true;
            var membershipBenefits = null;
            if (gm.basketResponse != null && gm.basketResponse.membershipBenefits != null && gm.basketResponse.membershipBenefits.length > 0) {
                membershipBenefits = gm.basketResponse.membershipBenefits;
            }
            if ($.trim(promoCode) != "") {
                gm.model.Id = basketId;
                gm.invalidpromo = false;
                gm.showCustomMsg = false;
                gm.model.promoCode = promoCode;
                $http.post(globalConfig.applyPromoCode, gm.model).success(function (data) {
                    gm.apiPendingTfs = false;
                    //remove the automatic application of the vouchers regardless of the response - to prevent double calling
                    sessionStorage.removeItem(gm.applyMembershipVoucherAfterRedirect);
                    if (data != null && data == "false") {
                        if (data != "false") {
                            gm.showCustomMsg = true;
                            gm.customMsg = data;
                        }
                        gm.invalidpromo = true;
                        $('.promo').show(0).delay(2000).hide(0);
                        return;
                    }
                    $scope.promoCode = null;
                    gm.invalidpromo = false;
                    gm.validpromo = true;
                    $('.promovalid').show(0).delay(2000).hide(0);
                    var dataResult = gm.serializedData(data.result.basket);
                    gm.basketResponse = dataResult;
                    //add prop which is missing from returned api data
                    addPropToShipFromStoreLineItem('disableGiftWrap');
                    if (gm.basketResponse != null && membershipBenefits != null && membershipBenefits.length > 0 && (gm.basketResponse.membershipBenefits == null || gm.basketResponse.membershipBenefits.length == 0)) {
                        gm.basketResponse.membershipBenefits = membershipBenefits;
                    }
                    initBasket(dataResult);
                })
                    .error(function (msg) {
                        if (msg.errorMessage != "false") {
                            gm.showCustomMsg = true;
                            gm.customMsg = msg.errorMessage;
                        }
                        gm.apiPendingTfs = false;
                        gm.invalidpromo = true;
                        $('.promo').show(0).delay(2000).hide(0);
                    })
                    .finally(function () {
                    });
            } else {
                gm.promonull = true;
                $('.promonull').show(0).delay(1200).hide(0);
            }
        }

        gm.physicalStoreStringConst = 'PhysicalStore';
        function addPropToShipFromStoreLineItem(prop) {
            angular.forEach(gm.basketResponse.deliveryPlans, function (plan) {
                if (plan.deliveryCenter.code == gm.physicalStoreStringConst) {
                    angular.forEach(plan.lineItems, function (planLineItem) {
                        angular.forEach(gm.basketResponse.lineItems, function (basketLineItem) {
                            if (planLineItem.productId.toLowerCase() == basketLineItem.productId.toLowerCase()) {
                                basketLineItem[prop] = true;
                            }
                        });
                    });
                }
            });
        }

        function cancelChangePostCode() {
            gm.basketResponse.postCode = $.cookie(BULKORDER_CONSTANTS.POSTCODE);
        }

        //Method to show the shipping methods after entering the valid Post code
        function showShippingGrid(countryCode, basketId, postCode, appliedShippingId) {
            $.cookie(BULKORDER_CONSTANTS.POSTCODE, postCode, { path: '/' });
            //var postCode_regex = /^[a-zA-Z0-9_/-]+$/;
            if (postCode != null && postCode != "") {
                //if (postCode_regex.test(postCode)) {
                $http.post(globalConfig.getDeliverysByPostCode, {
                    countryCode: countryCode,
                    basketId: basketId,
                    postCode: postCode,
                    appliedShippingId: appliedShippingId
                })
                    .success(function (data) {
                        $scope.postCodeSelected = true;
                        var dataResult = gm.serializedData(data);
                        gm.basketResponse = dataResult;
                        gm.basketResponse.postCode = $.cookie(BULKORDER_CONSTANTS.POSTCODE);
                    })
                    .error(function (msg) {
                    })
                    .finally(function () {
                    });

                //}
                //else {
                //    $scope.shippingSelected = false;
                //    $scope.postCodeSelected = false;
                //    ck.hideShippingAddress = true;
                //    ck.wrongPostCode = true;
                //    $timeout(function () { ck.wrongPostCode = false; }, 10000);

                //}
            }
        }
        function initBasket(basket) {
            loadGreetingCards();
            gm.unClaimedMembershipVouchers = [];
            if (basket == null || basket == undefined) {
                if (gm.basketResponse == null || gm.basketResponse == undefined) {
                    $http.post(globalConfig.getBasketUrl)
                        .success(function (data) {
                            gm.basketResponse = data;
                            initAddToBagQty();
                            gm.getUnClaimedVouchers();
                            gm.postCode = $.cookie(BULKORDER_CONSTANTS.POSTCODE);
                            if (gm.basketResponse != null && gm.basketResponse != undefined) {
                                angular.forEach(gm.basketResponse.lineItems, function (line) {
                                    var json = eval('(' + line.attributesJson + ')');
                                    line.slug = json.Slug;
                                    if (isJSON(line.customInfo2)) {
                                        line.customInfo2 = JSON.parse(line.customInfo2);
                                        line.parentProductId = line.customInfo2.ParentProductId;
                                    }
                                    line.updatedqty = line.qty;
                                    if (line.isGiftWrapApplied) {
                                        //line.giftWrappingInfo = gm.basketResponse.giftWrapOption.filter(x => x.id == line.giftWrapId.toUpperCase());
                                        line.giftWrappingInfo = [];
                                        angular.forEach(gm.basketResponse.giftWrapOption, function (opt) {
                                            if (opt.id.toUpperCase() == line.giftWrapId.toUpperCase()) {
                                                line.giftWrappingInfo.push(opt);
                                            }
                                        });
                                    }
                                });
                                gm.count = gm.basketResponse.lineItemCount;
                                gm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                                gm.changeBaseCurrency(gm.currencyCookie, false);
                                membershipDiscountPrice();
                                extractSubscription();
                                extractCustomInfo(gm.basketResponse);
                                updateBasketBadgeCount();
                                initGreetingCards();
                                initRibbons();

                                //NEW MULTI FULFILLMENT FUNCTIONALITY (Shipt From Store)
                                //ONLY if EnableShipFromStore == true (web.config)
                                if (isShipFromStoreEnabled() && gm.count > 0) {
                                    //add shipfromstore prop
                                    lineItemsAddPropShipFromStore();
                                    populateDeliveryPlans();
                                }

                                //paypal messaging refresh
                                renderPaypalMessaging();

                                //clearpay messaging render
                                renderClearpayMessaging();

                                gm.basketContainsMembership = checkBasketContainsMembership();
                                gm.basketContainsSubscription = checkBasketContainsSubscription();
                                gm.basketContainsVirtual = checkBasketContainsVirtual();

                                gm.potentialSavings = getBasketDiscountAmount();

                                gm.basketContainShipFromStoreItems = checkBasketContainShipFromStoreItems();

                                if (gm.isMultiFulfilmentEnabled) {
                                    gm.allItemsOOS = allItemsOOS();
                                    gm.someItemsOOS = someItemsOOS();
                                }

                                //check if membership discount needs to be applied
                                if (sessionStorage.getItem(gm.applyMembershipVoucherAfterRedirect) !== null) {
                                    applyMembershipVoucher();
                                }
                            }

                        })
                        .error(function (msg) {
                            // vm.errorMessage = msg.errorMessages;
                        })
                        .finally(function () {
                            // vm.saving = false;
                            //$("html, body").animate({ scrollTop: 0 }, "slow");
                        });
                }

            } else {
                gm.basketResponse = basket;
                if (gm.basketResponse != null && gm.basketResponse != undefined) {
                    angular.forEach(gm.basketResponse.lineItems, function (line) {
                        if (isJSON(line.customInfo2)) {
                            line.customInfo2 = JSON.parse(line.customInfo2);
                            line.parentProductId = line.customInfo2.ParentProductId;
                        }
                        line.updatedqty = line.qty;
                        if (line.isGiftWrapApplied) {
                            //line.giftWrappingInfo = gm.basketResponse.giftWrapOption.filter(x => x.id == line.giftWrapId.toUpperCase());
                            line.giftWrappingInfo = [];
                            angular.forEach(gm.basketResponse.giftWrapOption, function (opt) {
                                if (opt.id.toUpperCase() == line.giftWrapId.toUpperCase()) {
                                    line.giftWrappingInfo.push(opt);
                                }
                            });
                        }
                        if (line.isGreetingCardApplied) {
                            //line.greetingCardInfo = gm.basketResponse.greetingCardOption.filter(x => x.id == line.greetingCardId.toUpperCase());
                            line.greetingCardInfo = [];
                            angular.forEach(gm.basketResponse.greetingCardOption, function (opt) {
                                if (opt.id.toUpperCase() == line.greetingCardId.toUpperCase()) {
                                    line.greetingCardInfo.push(opt);
                                }
                            });
                        }

                    });
                    initAddToBagQty();
                    gm.getUnClaimedVouchers();
                    gm.count = gm.basketResponse.lineItemCount;
                    gm.postCode = $.cookie(BULKORDER_CONSTANTS.POSTCODE);
                    gm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                    gm.changeBaseCurrency(gm.currencyCookie, false);
                    membershipDiscountPrice();
                    extractCustomInfo(gm.basketResponse);
                    initGreetingCards();
                    initRibbons();

                    //paypal messaging refresh
                    renderPaypalMessaging();

                    //clearpay messaging render
                    renderClearpayMessaging();

                    //zip messaging
                    renderZipMessaging(gm.basketResponse.totalWithoutShipping.raw.withTax);

                    gm.basketContainsMembership = checkBasketContainsMembership();

                    gm.basketContainShipFromStoreItems = checkBasketContainShipFromStoreItems();

                    //add shipfromstore prop
                    lineItemsAddPropShipFromStore();

                    if (gm.isMultiFulfilmentEnabled) {
                        gm.allItemsOOS = allItemsOOS();
                        gm.someItemsOOS = someItemsOOS();
                    }

                    //check if membership discount needs to be applied
                    if (sessionStorage.getItem(gm.applyMembershipVoucherAfterRedirect) !== null) {
                        applyMembershipVoucher();
                    }
                }
            }
        }

        function membershipDiscountPrice() {
            if (gm.selectedCurrencySymbol == null || gm.selectedCurrencySymbol.length == 0) {
                gm.selectedCurrencySymbol = "£"
            }
            if (gm.basketResponse.membershipBenefits == null) {
                gm.membershipDiscountAmt = gm.selectedCurrencySymbol + ((gm.basketResponse.subTotal.raw.withTax / 100) * 20).toFixed(2);
            }
        }

        //multifillment FixDeliveryPlans
        function fixDeliveryPlans(goToCheckout = false, target = '') {
            //do nothing if we are not on a basket page
            if (!gm.isBasketPage) return;

            //return if already pending
            if (gm.apiPendingTfs) {
                return;
            }
            gm.apiPendingTfs = true;

            $http.get(MULTIFILFILLMENT.URL_FIX_DELIVERY_PLANS)
                .success(function (basketData) {
                    if (basketData != null && basketData != undefined) {
                        //set new props on the existing basket
                        setTfsBasketDataValidation(basketData);

                        //check if we need to redirect user to the checkout
                        if (goToCheckout && gm.tfsBasketDataValidation.validBasket) {
                            window.location.href = target;
                            return;
                        }
                        shipFromStoreModalHide();

                        //we initialise the basket to make sure the page is rendered as expected
                        //if changes where made
                        initBasket(basketData);

                        //populate line items with addons ON/OFF prop
                        lineItemsAddonsProp();
                    }
                })
                .error(function (msg) {

                })
                .finally(function () {
                    gm.apiPendingTfs = false;
                });
        }

        //multifillment PopulateDeliveryPlans
        function populateDeliveryPlans() {
            //do nothing if we are not on a basket page
            if (!gm.isBasketPage) return;

            gm.deliveryPlanApiPending = true;

            // basket before deliveryplan fetch
            var snapShotBasket = createBasketSnapshot(gm.basketResponse);

            $http.get(MULTIFILFILLMENT.URL_POPULATE_DELIVERY_PLANS)
                .success(function (basketData) {
                    if (basketData != null && basketData != undefined) {
                        //set new props on the existing basket
                        setTfsBasketDataValidation(basketData);
                        //we initialise the basket to make sure the page is rendered as expected
                        //if changes where made
                        initBasket(basketData);

                        //check if modal needs to be shown to the customer on basket load
                        //will show if needed on initial page load
                        if (!gm.tfsBasketDataValidation.validBasket && gm.shipFromStoreModalInitial && !gm.isMultiFulfilmentEnabled) {
                            //show addons modal
                            shipFromStoreModalShow();
                        }

                        //if multifulfilment is enabled we want to group invalid products and not show modal
                        if (!gm.tfsBasketDataValidation.validBasket && gm.shipFromStoreModalInitial && gm.isMultiFulfilmentEnabled) {
                            collectOutOfStockProducts(basketData);
                            fixDeliveryPlans();
                        }

                        if (gm.isMultiFulfilmentEnabled) {
                            if (!gm.tfsBasketDataValidation.validBasket) {
                                fixDeliveryPlans();
                            }
                            createSnapShotOfAddons(snapShotBasket, gm.basketResponse);
                        }

                        //populate line items with addons ON/OFF prop
                        lineItemsAddonsProp();
                    }
                })
                .error(function (msg) {

                })
                .finally(function () {
                    gm.deliveryPlanApiPending = false;
                    gm.showBasketWarning = showBasketWarning();
                });
        }

        gm.outofStockProducts = null;
        function collectOutOfStockProducts(basket) {
            let outofStockProducts = [];
            angular.forEach(basket.deliveryPlans, function (plan) {
                if (plan.deliveryCenter.code == "SupplierLocation") {
                    angular.forEach(plan.lineItems, function (item) {
                        outofStockProducts.push(item);
                    });
                }
            });
            gm.outofStockProducts = outofStockProducts;
        }

        gm.snapShotAddons = null;
        gm.basketTouched = false;
        function createSnapShotOfAddons(oldBasket, newBasket) {
            let oldAddons = [];
            angular.forEach(oldBasket.lineItems, function (oldLine) {
                angular.forEach(newBasket.lineItems, function (newLine) {
                    if (oldLine.productId.toLowerCase() == newLine.productId.toLowerCase() && typeof oldLine.isShipFromStore != 'undefined' && typeof newLine.isShipFromStore != 'undefined' && oldLine.isShipFromStore !== newLine.isShipFromStore) {
                        angular.forEach(oldBasket.lineItems, function (item) {
                            if (item.parentProductId == newLine.productId) {
                                oldAddons.push(item);
                                gm.basketTouched = true;
                            }
                        });
                    }
                });
            });
            gm.snapShotAddons = oldAddons;
        }

        function createBasketSnapshot(basket) {
            return JSON.parse(JSON.stringify(basket));
        }

        function checkApisPending() {
            return gm.apiPendingTfs || gm.deliveryPlanApiPending;
        }

        function setTfsBasketDataValidation(newBasket) {
            gm.tfsBasketDataValidation.validBasket = newBasket.validBasket;
            gm.tfsBasketDataValidation.validAddons = newBasket.validAddons;
            gm.tfsBasketDataValidation.validProducts = newBasket.validProducts;
            gm.tfsBasketDataValidation.disableGiftWrap = newBasket.disableGiftWrap;
        }

        function shipFromStoreModalShow() {
            $("#shipFromStoreModal").on('shown.bs.modal', function () {
                //adjust the backdrop
                $('.modal-backdrop.in').css({
                    "z-index": 9999998,
                });
            });
            $("#shipFromStoreModal").modal('show').on('hidden.bs.modal', function () {
                $("#shipFromStoreModal").off('hidden.bs.modal');
                gm.shipFromStoreModalInitial = false;
            });
        }

        function shipFromStoreModalHide() {
            $("#shipFromStoreModal").modal('hide');
        }

        //to add the quantity of product from dropdown
        function initAddToBagQty() {
            if (gm.maximumAddToBasketLimit > 0) {
                gm.basketQtyDropdown = [];
                for (var i = 1; i <= gm.maximumAddToBasketLimit; i++) {
                    gm.basketQtyDropdown.push(i);
                }
            }
        }

        gm.addMixLookbookToCart = addMixLookbookToCart;
        function addMixLookbookToCart(simpleProducts, subscriptionProductList, qty) {
            var model = [];
            if (subscriptionProductList != null && subscriptionProductList.length > 0) {
                $http.get("/Subscription/GetSubscriptionPlan?productId=" + subscriptionProductList[0].RecordId).then(function (success) {
                    gm.subscriptionPlan = success.data.result;
                    angular.forEach(subscriptionProductList, function (data, index) {
                        model.push({ stockCode: data.StockCode, productId: data.RecordId, qty: qty, subscriptionPlanId: gm.subscriptionPlan.recordId, isSubscription: true, displayOrder: index });
                    });
                    angular.forEach(simpleProducts, function (data, index) {
                        model.push({ stockCode: data.StockCode, productId: data.RecordId, qty: qty, displayOrder: index });
                    });
                    gm.addToLookBook(model);
                }, function (error) { });
            }
            else {
                angular.forEach(simpleProducts, function (data, index) {
                    model.push({ stockCode: data.StockCode, productId: data.RecordId, qty: qty, displayOrder: index });
                });
                gm.addToLookBook(model);
            }
        }
        gm.addToLookBook = addToLookBook;
        function addToLookBook(model) {
            var isAlreadyExistInBasket = false;
            $http.post(globalConfig.bulkAddproduct, model)
                .success(function (data) {
                    var dataResult = gm.serializedData(data.result);
                    if (data.messageCode == 'C002') {
                        gm.errorMessage = data.message;
                        $('.alert').show(0).delay(4000).hide(0);
                    }
                    gm.basketResponse = dataResult;
                    PubSub.publish("addToCartBulk", gm.basketResponse);
                    var count = 0;
                    if (gm.basketResponse != null) {
                        if (gm.basketResponse.lineItems != null) {
                            angular.forEach(gm.basketResponse.lineItems, function (line) {
                                if (line.parentProductId == gm.emptyGuid) {
                                    count = count + line.qty;
                                }
                                var json = eval('(' + line.attributesJson + ')');
                                line.slug = json.Slug;
                                isAlreadyExistInBasket = false;
                            });
                            gm.count = gm.basketResponse.lineItemCount;
                        }
                    }
                    redirectToOffers(gm.basketResponse.id, isAlreadyExistInBasket);
                }).error(function () {
                    gm.wrongFormatMessage = true;
                    $('.wrongFormatError').show(0).delay(3000).hide(0);
                });
        }
        function addLookbookToCart(data, qty) {
            var isAlreadyExistInBasket = false;
            var model = [];
            angular.forEach(data, function (stockCode) {
                model.push({ stockCode: stockCode, qty: qty })
            });

            $http.post(globalConfig.bulkAddproduct, model)
                .success(function (data) {
                    var dataResult = gm.serializedData(data.result);
                    if (data.messageCode == 'C002') {
                        gm.errorMessage = data.message;
                        $('.alert').show(0).delay(4000).hide(0);
                    }
                    gm.basketResponse = dataResult;
                    PubSub.publish("addToCartBulk", gm.basketResponse);
                    var count = 0;
                    if (gm.basketResponse != null) {
                        if (gm.basketResponse.lineItems != null) {
                            angular.forEach(gm.basketResponse.lineItems, function (line) {
                                if (line.parentProductId == gm.emptyGuid) {
                                    count = count + line.qty;
                                }
                                var json = eval('(' + line.attributesJson + ')');
                                line.slug = json.Slug;
                                isAlreadyExistInBasket = false;
                            });
                            gm.count = gm.basketResponse.lineItemCount;
                        }
                    }
                    redirectToOffers(gm.basketResponse.id, isAlreadyExistInBasket);
                }).error(function () {
                    gm.wrongFormatMessage = true;
                    $('.wrongFormatError').show(0).delay(3000).hide(0);
                });
        }

        function pushEventToOmnilytics(eventName, data) {

            if (eventName == 'addToBasket' && data != null) {
                // in this case data is the server response of the add to basket calls
                // in case the item is removed or qty reduced, data would also contain product field having the product which was removed. 

                if (data.lineItems != null && data.lineItems.length > 0) {
                    var eventData = {
                        product: data.productRemoved,
                        basket: { id: null, lines: [], totalCost: null, totalItems: null, tax: null }
                    };
                    eventData.id = data.id;
                    eventData.basket.totalItems = data.lineItemCount;
                    eventData.basket.totalCost = data.subTotal.raw.withoutTax;
                    eventData.basket.tax = data.grandTotal.raw.tax;
                    angular.forEach(data.lineItems, function (line) {
                        var li = {
                            id: line.id,
                            basketId: data.id,
                            stockCode: line.stockCode,
                            name: line.name,
                            qty: line.qty,
                            price: line.price.raw.withoutTax,
                            tax: line.price.raw.tax,
                            manufacturer: line.Manufacture,
                            'img': line.image
                        };
                        eventData.basket.lines.push(li);
                        if (line.productId.toLowerCase() == data.product.productId.toLowerCase() && data.productRemoved == null) {
                            var prodDetail = angular.copy(line);
                            prodDetail.qty = data.product.qty /// set the actual qty that was requested to be aded instead of final  item qty
                            prodDetail.basketId = data.product.basketId;
                            eventData.product = prodDetail;
                        }
                        PubSub.publish("addToCart", eventData);
                    });
                }
            }
        }

        function addToBasket(recordId, qty, displayOrder, isSubscription, isMembership = 0, redirect = false, membershipUpgrade = false) {
            gm.apiPendingTfs = true;
            if (gm.currentlySelectedProductId !== gm.emptyGuid) {
                recordId = gm.currentlySelectedProductId;
                $('section.pdp-modal-product button.cart-add-btn').prop('disabled', true);
            }

            if (gm.memberShipAlert != null && gm.memberShipAlert.length > 0) {
                alerts.error(gm.memberShipAlert);
                $('section.pdp-modal-product button.cart-add-btn').prop('disabled', false);
                return;
            }

            if (isSubscription == undefined)
                isSubscription = false;
            if ($scope.addToBagInProgress) {
                $('section.pdp-modal-product button.cart-add-btn').prop('disabled', false);
                return;
            }
            $scope.addToBagInProgress = true;

            //variable to check if product to be added is already exist in basket or not
            //to be used in finally block when redirecting it to offer page. 
            //if product already exists in basket that means it's a qty update or deletion hence no offer page redirection. 
            var isAlreadyExistInBasket = false;

            if (displayOrder >= 0) {
                gm.displayOrder = displayOrder;
            } else {
                gm.displayOrder = gm.basketResponse.lineItems.length + 1;
            }
            var basketId = gm.basketResponse != null ? gm.basketResponse.id : "";
            var itemType = 0;
            var prodInBasket = null;
            if (gm.basketResponse != null) {
                if (gm.basketResponse.lineItems != null) {
                    angular.forEach(gm.basketResponse.lineItems, function (line) {
                        if (line.productId.toLowerCase() == recordId.toLowerCase()) {
                            itemType = line.itemType;
                            // this line is used in omnilytics  incase of product removal from basket
                            prodInBasket = {
                                'id': line.productId,
                                'name': line.name,
                                basketId: basketId,
                                'stockCode': line.stockCode,
                                'price': line.price,
                                'manufacturer': line.manufacturer,
                                'category': line.category,
                                'qty': qty,
                                'image': line.image
                            };
                            isAlreadyExistInBasket = true;
                        }
                    });
                }
            }
            initAddToBagQty();
            var itemGroupId = 0;
            if (gm.couponProvider == 'Givex')
                itemGroupId = 7;
            var prod = {
                "basketId": basketId,
                "productId": recordId,
                "qty": qty,
                "displayOrder": gm.displayOrder,
                "itemType": itemType,
                "issubscription": isSubscription,
                "isMembership": isMembership,
                "itemGroupId": itemGroupId
            };
            gm.couponProvider = '';
            //var eventData = { product: prodInBasket, basket: { id: null, lines: [], totalCost: null, totalItems: null, tax: null } };
            $http.post(globalConfig.addToBasket, prod)
                .success(function (data) {
                    $scope.addToBagInProgress = false;
                    //validate the basket and return false if  basket item is greater than the count set in basket settings
                    if (data != null && data.isValid == false) {
                        gm.maximumBasketItemError = true;
                        alerts.error(data.message);
                        //retain the old basket quantity when item exceeds the required qty
                        angular.forEach(gm.basketResponse.lineItems, function (line) {
                            if (line.productId == recordId) {
                                line.qty = line.updatedqty;
                                // this line is used in omnilytics  incase of product removal from basket 
                            }
                        });
                        $('section.pdp-modal-product button.cart-add-btn').prop('disabled', false);
                        return;
                    }
                    if (data != null && data != false) {
                        if (data.messageCode != null && data.messageCode.length > 0 && (data.messageCode == BULKORDER_CONSTANTS.ITEM_STOCK_UNAVAILABLE || data.messageCode == BULKORDER_CONSTANTS.ITEM_STOCK_UNAVAILABLE)) {
                            alerts.error(data.message);
                            $('section.pdp-modal-product button.cart-add-btn').prop('disabled', false);
                            if (data == null || data.result == null || data.result.lineItems == null || data.result.lineItems.length == 0) {
                                return;
                            } else {
                                angular.forEach(data.result.lineItems, function (value, key) {
                                    if (value.stockCode == value.stockCode) {
                                        gm.isProductExist = true;
                                    }
                                });
                            }

                        }
                    }
                    updateBasket(data);
                    //gm.removeProductToWishlist(recordId);
                    //PubSub.publish("addToCart", eventData);
                    gm.basketResponse.productRemoved = prodInBasket /// this is assigned in case of basket item removal since the response would not have any product 
                    gm.basketResponse.product = { productId: recordId, qty: qty, basketId: basketId };/// this is assigned to pass the actual qty change.
                    pushEventToOmnilytics('addToBasket', gm.basketResponse);
                    if (typeof _itq != "undefined") {
                        if (qty < 1) {
                            _itq.push(["_trackUserEvent", "remove from basket",
                                {
                                    Product: {
                                        ID: recordId
                                    }
                                },
                                "Remove from Basket"
                            ]);
                        } else {
                            if (gm.basketResponse != null && gm.basketResponse.lineItems != null && gm.basketResponse.lineItems.length > 0) {
                                gm.addToBasketProduct = null;
                                angular.forEach(gm.basketResponse.lineItems, function (value, key) {
                                    if (value.productId != null && recordId != null && value.productId.toLowerCase() == recordId.toLowerCase()) {
                                        gm.addToBasketProduct = value;
                                        $('section.pdp-modal-product button.cart-add-btn').prop('disabled', false);
                                        return;
                                    }
                                });
                                if (gm.addToBasketProduct != null) {
                                    _itq.push(["_trackUserEvent", "add to basket",
                                        {
                                            Product: {
                                                ID: gm.addToBasketProduct.productId,
                                                Image: gm.addToBasketProduct.image,
                                                Price: gm.addToBasketProduct.price.formatted.withTax,
                                                Subbrand: gm.addToBasketProduct.subbrand,
                                                Productname: gm.addToBasketProduct.name,
                                                Brand: gm.addToBasketProduct.brand
                                            }
                                        },
                                        "Add to Basket"
                                    ]);
                                }
                            }
                        }
                    }

                    //check if we need to stay in the basket
                    //this is for membership upgrades from basket page
                    if (membershipUpgrade) {
                        isAlreadyExistInBasket = true; //this is to not trigger redirect to offers page
                    }

                    //redirect to offer page
                    if (data.messageCode != 'C002' || gm.isProductExist || gm.engravingFailedAction === 'continue') {
                        if (typeof addToBagAB !== 'undefined' && typeof showAddToBagABModal == 'function' && addToBagAB == true) {
                            showAddToBagABModal(gm.basketResponse.lineItems);
                        }
                        else {
                            if (gm.isProductExist) {
                                $timeout(function () {
                                    redirectToOffers(recordId, isAlreadyExistInBasket, redirect);
                                }, 3000);
                            } else {
                                redirectToOffers(recordId, isAlreadyExistInBasket, redirect);
                            }
                        }
                        gm.isProductExist = false;
                    }

                    //engraving failed modal actions
                    if (gm.engravingFailedAction === 'remove' && gm.engravingProduct) {
                        engravingFiledActions();
                    }
                    if (isMembership) {
                        window.location.reload();
                        return;
                    }
                    //UPDATE BASKET IF SHIP BASKET PAGE AND SHIP FROM STORE ENABLED
                    if (isShipFromStoreEnabled() && gm.count > 0) {
                        populateDeliveryPlans();
                    }

                    gm.basketContainsMembership = checkBasketContainsMembership();

                    //if we are upgrading from account area we need to redirect user to basket once done
                    if (membershipUpgrade && data.messageCode != 'C002') {
                        window.location.href = "/Basket";
                    }

                    gm.apiPendingTfs = false;
                })
                .error(function (msg) {
                    $('section.pdp-modal-product button.cart-add-btn').prop('disabled', false);
                    gm.apiPendingTfs = false;
                })
                .finally(function () {
                    gm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                    gm.changeBaseCurrency(gm.currencyCookie, false);
                    $('section.pdp-modal-product button.cart-add-btn').prop('disabled', false);
                    if (gm.isMultiFulfilmentEnabled) {
                        collectOutOfStockProducts(gm.basketResponse);
                    }
                });
        };


        function checkBasketContainsMembership() {
            var membershipLines = [];
            angular.forEach(gm.basketResponse.lineItems, function (line) {
                if (line.isMembership) {
                    membershipLines.push(line);
                }
            });
            return membershipLines.length > 0 ? true : false;
        }

        function checkBasketContainsSubscription() {
            var subLines = [];
            angular.forEach(gm.basketResponse.lineItems, function (line) {
                if (line.isSubscription) {
                    subLines.push(line);
                }
            });
            return subLines.length > 0 ? true : false;
        }

        function checkBasketContainsVirtual() {
            var virLines = [];
            angular.forEach(gm.basketResponse.lineItems, function (line) {
                if (line.itemGroupId == 7) {
                    virLines.push(line);
                }
            });
            return virLines.length > 0 ? true : false;
        }

        function redirectToOffers(productId, isAlreadyExistInBasket, redirect = false) {
            if (!isAlreadyExistInBasket || gm.engravingFailedAction === 'continue' || redirect) {
                if (gm.basketResponse != null && gm.basketResponse != undefined && gm.basketResponse.lineItems != null && gm.basketResponse.lineItems.length > 0) {
                    //get the last added item sub-brand 
                    //var lastAddedItem = gm.basketResponse.lineItems.find(i => i.productId.toLowerCase() == productId.toLowerCase());
                    var lastAddedItem = '';
                    angular.forEach(gm.basketResponse.lineItems, function (line) {
                        if (line.productId.toLowerCase() == productId.toLowerCase())
                            lastAddedItem = line;
                    });
                    if (lastAddedItem) {
                        //store sub-brand in cookie
                        $.cookie("_stk", lastAddedItem.stockCode, { path: '/' });
                    }
                }
                //redirect to offer page
                if (gm.offerCategoryName != null && gm.offerCategoryName != "")
                    window.location.href = globalConfig.offerUrl + "/?categoryType=" + gm.offerCategoryName;
                else
                    window.location.href = globalConfig.offerUrl;
            }
        }

        function removeProductToWishlist(recordId) {
            $http.post(globalConfig.removeProductFromWishlist, { id: recordId })
                .success(function (data) {
                    PubSub.publish("wishListData", data);
                    //window.location.reload();
                })
                .error(function (msg) {
                })
                .finally(function () {
                });
        };

        function getShippingMethods(countryCode) {

            $http.post(globalConfig.getShippingMethods, { 'countryCode': countryCode })
                .success(function (data) {
                    gm.basketResponse.shippingMethods = data;
                })
                .error(function (msg) {
                    // vm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    // vm.saving = false;
                    //$("html, body").animate({ scrollTop: 0 }, "slow");
                });
        }

        function updateQtyAndAdd(productId, newQty, oldQty, displayOrder) {
            gm.updateQty = 0;
            if (newQty == oldQty || !oldQty) {
                return gm.basketResponse;
            } else {
                if (newQty > oldQty) {
                    gm.updateQty = newQty - oldQty;
                } else {
                    gm.updateQty = -(oldQty - newQty);
                }
                gm.addToBasket(productId, gm.updateQty, displayOrder);
            }
        };

        function updateShipping(id) {
            $http.post(globalConfig.updateShipping, { id: gm.basketResponse.id, shippingId: id, nominatedDelivery: null })
                .success(function (data) {
                    var dataResult = gm.serializedData(data.basket);
                    gm.basketResponse = dataResult;
                    angular.forEach(data.basket.shippingMethods, function (obj, key) {
                        if (obj.id == id) {
                            gm.basketResponse.isPriceOnRequest = obj.isPriceOnRequest;
                        }
                    });
                })
                .error(function (msg) {
                    // vm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    // vm.saving = false;
                    //$("html, body").animate({ scrollTop: 0 }, "slow");
                });
        };

        function removePromoCode(id, promoCode) {
            gm.apiPendingTfs = true;
            var membershipBenefits = null;
            gm.deletedPromoCode = promoCode;
            if (gm.basketResponse != null && gm.basketResponse.membershipBenefits != null && gm.basketResponse.membershipBenefits.length > 0) {
                membershipBenefits = gm.basketResponse.membershipBenefits;
            }

            $http.post(globalConfig.removePromoCode, { id: id, promoCode: promoCode })
                .success(function (data) {
                    gm.apiPendingTfs = false;
                    gm.validpromo = false;
                    var dataResult = gm.serializedData(data.result.basket);
                    gm.basketResponse = dataResult;
                    //add prop which is not returned but required by html
                    addPropToShipFromStoreLineItem('disableGiftWrap');
                    if (gm.basketResponse != null && membershipBenefits != null && membershipBenefits.length > 0 && (gm.basketResponse.membershipBenefits == null || gm.basketResponse.membershipBenefits.length == 0)) {
                        gm.basketResponse.membershipBenefits = membershipBenefits;
                    }
                    initBasket(dataResult);
                })
                .error(function (msg) {
                    gm.apiPendingTfs = false;
                })
                .finally(function () {
                });
        };

        function addProductsExcel(line) {
            gm.errorMessage = '';
            gm.wrongFormatError = '';
            gm.basketMessage = '';
            gm.stockUnavailable = false;
            $scope.bulkOrder = [];
            var rows = line.split("\n");
            angular.forEach(rows, function (value, key) {
                $scope.bulkOrder.push({ stockCode: rows[key].split(",")[0], qty: rows[key].split(",")[1], basketId: "" })
            });
            angular.forEach($scope.bulkOrder, function (item, key) {
                if (item != undefined) {
                    angular.forEach($scope.bulkOrder, function (i, k) {
                        if (i != undefined && item.stockCode == i.stockCode && key != k) {
                            gm.errorMessage = " ";
                        }
                    });
                }
            });
            if (gm.errorMessage) {
                $('.stockError').show(0).delay(3000).hide(0);
                return;
            }
            $http.post(globalConfig.bulkAddproduct, $scope.bulkOrder)
                .success(function (data) {
                    var dataResult = gm.serializedData(data.result);
                    gm.basketResponse = dataResult;
                    var count = 0;
                    if (gm.basketResponse != null) {
                        if (gm.basketResponse.lineItems != null) {
                            angular.forEach(gm.basketResponse.lineItems, function (line) {
                                if (line.parentProductId == gm.emptyGuid) {
                                    count = count + line.qty;
                                }
                                var json = eval('(' + line.attributesJson + ')');
                                line.slug = json.Slug;
                            });
                            gm.count = gm.basketResponse.lineItemCount;
                        }
                    }
                    $("#AddToBasketModel").modal("hide");
                    $("#bulkOrderMessage").modal();
                    if (data.message != null && data.message.length > 0)
                        gm.notFoundLength = data.message.split(",").length;
                    if (data.messageCode == BULKORDER_CONSTANTS.STOCK_UNAVAILABLE) {
                        gm.stockUnavailable = true;
                        $('.stockUnavailable').show(0).delay(3000).hide(0);
                    }
                    if (data.message) {
                        if (data.messageCode == BULKORDER_CONSTANTS.STOCK_AVAILABLE) {
                            gm.basketMessage = data.message;
                        }
                        if (data.message) {
                            if (data.messageCode == BULKORDER_CONSTANTS.SUCCESS)
                                gm.basketMessage = data.message
                        } else {
                            gm.basketMessage = data.message;
                        }
                        return;
                    }
                }).error(function () {
                    gm.wrongFormatMessage = true;
                    $('.wrongFormatError').show(0).delay(3000).hide(0);
                });
        };

        //#endregion
        gm.addToWishlistAction = false;
        gm.redeemSaVoucherAction = false;
        function userLogin(model, modal = false) {
            let url = globalConfig.signIn;
            if (modal) {
                url = '/TFSAccount/SignIn';
            }
            gm.saving = false;
            gm.errorMessage = null;
            gm.success = false;
            $(".alertBlock").hide();
            $http.post(url, model)
                .success(function (data) {
                    if (data) {
                        if (!data.isValid != null && typeof data.errorMessages != 'undefined' && data.errorMessages.length > 0) {
                            gm.errorMessage = data.errorMessages;
                            return;
                        }
                        if (typeof _itq != "undefined") {
                            _itq.push(["_trackUserEvent", "sign in",
                                {
                                    "Customer": { "Email": model.username }
                                },
                                "Sign In"
                            ]);
                        }

                        $timeout(function () {
                            gm.isChecked = $.cookie(model.username);
                        }, 10000);
                        $("#login-modal").modal('hide');
                        $.cookie('IsUserLoggedIn', true, { path: '/' });
                        if ($scope.global_login || gm.forPaymentUpdate || gm.addToWishlistAction || gm.redeemSaVoucherAction) {
                            if (gm.addToWishlistAction) {
                                sessionStorage.setItem('addToWishlist', true);
                            }
                            window.location.reload();
                        } else {
                            const returnUrl = 'returnUrl';
                            let params = getAllQuerryParams(window.location.search);
                            if (params.hasOwnProperty(returnUrl)) {
                                const url = params[returnUrl];
                                window.location.href = url;
                            }
                            else {
                                window.location.href = window.location.origin + '/myaccount';
                            }

                        }

                    }
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    gm.saving = false;
                    gm.signing = false;
                });
        }

        //extract search params to array
        function getAllQuerryParams(search) {
            let paramsObj = {};
            let params = new URLSearchParams(search);
            for (let key of params.keys()) {
                paramsObj[key] = params.get(key)
            }
            return paramsObj;
        }

        function isPasswordPolicyMeet(flag, form, pwdId, cnfPwdId) {
            if (!flag)
                form[pwdId].$valid = false;
            else
                form[pwdId].$valid = true;
            if (form[pwdId].$modelValue != form[cnfPwdId].$modelValue)
                form[cnfPwdId].$valid = false;
            else
                form[cnfPwdId].$valid = true;
            if (form[pwdId].$valid && form[cnfPwdId].$valid)
                return true;
            else
                return false;
        }

        function checkPassword(form, pwdId, cnfPwdId) {
            $timeout.cancel(gm.passwordCheckTimeout1);
            $timeout.cancel(gm.passwordCheckTimeout2);
            if (!gm.myPlugin) {
                gm.myPlugin = $("input[id='" + pwdId + "']").password_strength();
            }
            var resp = false;
            gm.passwordCheckTimeout1 = $timeout(function () {
                resp = gm.myPlugin.metReq();
            }, 1500);
            gm.passwordCheckTimeout2 = $timeout(function () {
                gm.isPasswordPolicyMeet(resp, form, pwdId, cnfPwdId);
            }, 1500);
        }

        function registration(model, isRedeem) {
            $scope.global_login = false;
            $scope.signin = false;
            $scope.register = true;
            gm.registering = true;
            gm.saving = false;
            gm.errorMessage = null;
            gm.success = false;
            $(".alertBlock").hide();
            // if (!gm.isPasswordPolicyMeet)
            //     return false;

            gm.model.registerViewModel.NewsLetterSubscribed = gm.model.registerViewModel.notifyByEmail;
            $http.post(globalConfig.register, model)
                .success(function (data) {
                    if (data) {
                        if (!data.isValid != null && typeof data.errorMessages != 'undefined' && data.errorMessages.length > 0) {
                            gm.errorMessage = data.errorMessages;
                            return;
                        }
                        $.cookie('IsUserLoggedIn', true, { path: '/' });
                        if (isRedeem)
                            window.location.href = "/redeem";
                        else {
                            var returnStr = "?returnUrl=";
                            if (window.location.search != null && window.location.search.indexOf(returnStr) > -1) {
                                window.location.href = window.location.search.replace(returnStr, '');
                            }
                            else {
                                window.location.href = "/MyAccount";
                            }
                        }

                    }
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    gm.registering = false;
                });
        }

        function setWidgetId(widgetId) {
            gm.widgetId = widgetId;
            vcRecaptchaService.execute(widgetId);
        }

        gm.captchaExpiration = captchaExpiration;

        function captchaExpiration() {
            vcRecaptchaService.reload(gm.widgetId);
            vcRecaptchaService.execute(gm.widgetId);
        }

        function login(model, captchaVerificationEnable, modal = false) {
            var allowuserLogin = true;
            if (captchaVerificationEnable == true) {
                allowuserLogin = false;
                var recapResponse = vcRecaptchaService.getResponse(gm.widgetId);
                if (recapResponse === "" || recapResponse.length == 0) {
                    allowuserLogin = false;
                    alerts.error('Please resolve the captcha and submit!');
                }
                else {
                    allowuserLogin = true;
                    model.captchaResponse = recapResponse;
                }
            }
            if (allowuserLogin) {
                $scope.signin = true;
                gm.signing = true;
                $scope.register = false;
                $scope.global_login = false;
                gm.userLogin(model, modal);
            }
        }

        function globalLogin(model) {
            $scope.signin = false;
            gm.signing = true;
            $scope.register = false;
            $scope.global_login = true;
            gm.userLogin(model);
        }

        function forgotPassword(model) {
            gm.resettingPassword = true;
            $(".alertBlock").hide();
            $http.post(globalConfig.forgotPassword, model)
                .success(function (data) {
                    gm.errorMessage = null;
                    if (data != null) {
                        if (!data.isValid && typeof data.errorMessages != 'undefined' && data.errorMessages.length > 0) {
                            gm.errorMessage = data.errorMessages;
                            return;
                        } else {
                            gm.passwordResetSuccess = true;
                        }
                    }
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    gm.resettingPassword = false;
                });
        };

        function registerCompanyRequest(model) {
            if (model.country == undefined)
                model.country = gm.defaultCountry;
            $scope.changeForm.$setSubmitted();
            $scope.registrationAlert = true;
            gm.errorMessage = null;
            $(".alertBlock").fadeIn();
            if (!gm.isPasswordValid)
                return false;
            $http.post(globalConfig.companyRegisterUrl, model)
                .success(function (resp) {
                    if (resp.isValid) {
                        if (resp.message) {
                            gm.accountCreated = true;
                            $('.accountCreated').show(0).delay(3000).hide(0);
                        } else {
                            gm.requestSuccess = true;
                            $('.requestSuccess').show(0).delay(3000).hide(0);
                        }
                        $timeout(function () {
                            window.location.reload();
                        }, 5000);
                    }
                    ;
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    $timeout(function () {
                        $(".alertBlock").fadeOut();
                    }, 10000);
                });
        }

        //#region blogs

        function getallblogs(page) {
            location.href = 'GetAllBlogs?currentpage=' + page + ''
        }

        function getallblogsbycategory(page, category) {

            location.href = 'GetBlogByCategory?category=' + category + '&currentpage=' + page + ''
        }

        function getBlogByCategory(id, page) {
            $http.post(globalConfig.getBlogByCategory, { category: id, currentpage: page })
                .success(function (data) {
                    var dataResult = gm.serializedData(data);
                    gm.basketResponse = dataResult;

                })
                .error(function (msg) {
                    // vm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    // vm.saving = false;
                    //$("html, body").animate({ scrollTop: 0 }, "slow");
                });


        }

        //function getBlogByCategory(id, page) {

        //    $http.post(globalConfig.getBlogsbyCategory, {category: id, currentpage: page})
        //        .success(function (data) {

        //            gm.blogReponse = data;

        //        })
        //        .error(function (msg) {
        //            // vm.errorMessage = msg.errorMessages;
        //        })
        //        .finally(function () {
        //            // vm.saving = false;
        //            //$("html, body").animate({ scrollTop: 0 }, "slow");
        //        });


        //}

        function initblogs(id) {
            $http.post(globalConfig.getallblogs, { id: id })
                .success(function (data) {

                    gm.blogReponse = data;

                })
                .error(function (msg) {
                    // vm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    // vm.saving = false;
                    //$("html, body").animate({ scrollTop: 0 }, "slow");
                });
        }

        //#endregion blogs

        function currencySettings(currencyCode) {
            var data = { currency: currencyCode };
            $http.post(globalConfig.currencySettingUrl, data)
                .success(function () {
                    window.location.reload();
                })
                .error(function (msg) {
                })
                .finally(function () {
                });
        };

        function getPaymentMethods() {
            $http.post(globalConfig.paymentMethodsUrl)
                .success(function (data) {
                    gm.paymentMethods = data;
                })
                .error(function (msg) {
                })
                .finally(function () {
                });
        };

        function newsLetterSubscription(email) {
            gm.emailinvalid = false;
            gm.subssuccess = false;
            var email_regex = /^[_a-z0-9]+(\.[_a-z0-9]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})$/;
            if (!email_regex.test(email.toLowerCase())) {
                gm.emailinvalid = true;
                $('.newsletteralert').show(0).delay(2000).hide(0);
            }
            if (email == "" || email == null) {
                gm.emailinvalid = true;
                $('.newsletteralert').show(0).delay(2000).hide(0);
            }
            var model = { email: email, notifyByEmail: true, newsLetterSubscribed: true, sourceProcess: gm.sourceProcess }
            if (gm.emailinvalid == false) {
                $http.post(globalConfig.newsLetterSubscription, { newsletter: model })
                    .success(function (data) {
                        gm.customerEmail = '';
                        if (data == true) {
                            gm.subssuccess = true;
                            $.cookie("NewsLetterSubscribed", email, { path: '/', expires: 1000 });
                            gm.isNewsLetterSubscribed = $.cookie("NewsLetterSubscribed");
                        } else {
                            gm.alreadySubscribed = true;
                            $('.newsletteralready').show(0).delay(2000).hide(0);
                        }
                    })
                    .error(function (msg) {
                        gm.alreadySubscribed = true;
                        $('.newsletteralert').show(0).delay(2000).hide(0);
                    })
                    .finally(function () {

                    });
            }

        }

        function showBasket(value) {
            if (value)
                gm.activeClass = 'active';
            else
                gm.activeClass = '';
        }

        function openQuickBasketModal() {
            $("#AddToBasketModel").modal();
        };

        function nRows(num) {
            return new Array(num);
        }

        //loadPCAScript(scriptLoader, globalConfig.pcaAccessCode)

        function productPrice(isChecked) {
            gm.incVat = (isChecked) ? false : true;
            $.cookie('incVat', gm.incVat, { path: '/' });
        };

        function socialSignIn(provider) {
            //$http.post(globalConfig.socialSignInUrl, {provider: provider}).success(function (data) {

            //});

            var Form = document.createElement('form');
            Form.setAttribute('method', 'post');
            Form.setAttribute('action', '/Account/SocialSignIn');
            var providertag = document.createElement('input');
            providertag.setAttribute('type', 'hidden');
            providertag.setAttribute('name', 'provider');
            providertag.setAttribute('value', provider);
            Form.appendChild(providertag);

            document.getElementsByTagName('body')[0].appendChild(Form);
            Form.submit();
        };

        function getSocialSettings() {
            $http.post("/Account/GetSocialSettings").then(function (success) {
                gm.model.socialSettings = success.data;
            }, function (error) {
            });
        }

        function getBillingCountries() {
            $http.post(globalConfig.getBillingCountriesUrl)
                .success(function (data) {
                    if (data.length > 0) {
                        gm.countries = data;
                    }
                })
                .error(function (msg) {

                })
                .finally(function () {

                });
        }

        function basketDetails(basketId) {
            gm.basketDetailView = true;
            gm.currentBasket = gm.baskets.find(function (basket) {
                return basket.id == basketId
            });
        }

        function hideBasketDetail() {
            gm.basketDetailView = false;
        }

        PubSub.subscribe('addToCart', function (eventData) {
            if (eventData != null && dataLayer && typeof omnilytics != 'undefined' && omnilytics) {
                if (eventData.product != null) {
                    var prod = eventData.product
                    var data = dataLayer[0];
                    var entity = {
                        'basketId': prod.basketId,
                        'name': prod.name,
                        'id': prod.productId,
                        'stockCode': prod.stockCode,
                        'price': prod.price.raw.withTax,
                        'brand': prod.manufacturer,
                        'category': prod.category,
                        'quantity': prod.qty,
                        'img': prod.image
                    };
                    data["entity"] = JSON.stringify(entity);
                    data["entityId"] = prod.productId;
                    data["entityName"] = prod.name;
                    data["entityType"] = "product";
                    data["basketItems"] = JSON.stringify(eventData.basket.lines);
                    data["basketItemCount"] = eventData.basket.lines.length ? eventData.basket.totalItems : 0;
                    data["basketTotal"] = eventData.basket.totalCost;
                    data["tax"] = eventData.basket.tax;
                    dataLayer[0] = data;
                    data["action"] = "addToCart";
                    if (eventData.basket.lines.length == 0 || prod.qty < 1) {
                        data["eventType"] = "basketItemRemoved";
                        omnilytics.emit('basketItemRemoved', null);

                    } else {
                        data["eventType"] = "basketItemAdded";
                        omnilytics.emit('basketItemAdded', null);

                    }


                }
            }
        });
        PubSub.subscribe('registerUser', function (eventData) {
            if (eventData != null && dataLayer && omnilytics && gm.publishPubSub) {
                if (eventData.email != null) {
                    var user = eventData
                    var data = dataLayer[0];
                    var entity = {
                        'email': user.email,
                        'recordId': user.recordId,
                        'notifyNone': user.notifyNone,
                        'notifyBySms': user.notifyBySMS,
                        'notifyEmail': user.notifyByEmail,
                        'notifyPost': user.notifyByPost
                    };
                    data["entity"] = JSON.stringify(entity);
                    data["entityName"] = user.email;
                    data["entityType"] = "customer";
                    data["action"] = "registerUser";
                    data["eventType"] = "customerCreated";
                    omnilytics.emit('customerCreated', null);
                }
            }
            gm.publishPubSub = false;
        });

        function onTextFocus(event) {
            event.target.select();
        }

        function addQuoteToBasket(id, action) {
            if (gm.basketResponse != null && gm.basketResponse.lineItems.length != 0) {
                $("#quoteDetailModal").modal("hide");
                $("#mergeBasketModal").modal();
                return;
            }
            gm.basketAction(id, action);
        }

        function basketAction(quoteId, action) {
            $http.post(globalConfig.addQuoteToBasketUrl, { basketId: quoteId, basketAction: action })
                .success(function (data) {
                    var dataResult = gm.serializedData(data);
                    gm.basketResponse = dataResult;
                    $("#quoteDetailModal").modal("hide");
                    $("#mergeBasketModal").modal("hide");
                    if (gm.basketResponse != null && gm.basketResponse != undefined) {
                        gm.count = gm.basketResponse.lineItemCount;
                        var scroll = $(window).scrollTop();
                        if (scroll >= 200) {
                            $("#miniBasket").addClass("fix-to-top");
                        } else {
                            $("#miniBasket").removeClass("fix-to-top");
                        }
                        $('.cartopen').addClass('active');
                        $timeout(function () {
                            $(".cartopen").removeClass("active");
                            $("#miniBasket").removeClass("fix-to-top");
                        }, 10000);
                    }
                }).finally(function () {
                });
        }

        function removeQuoteBasket() {
            $http.post(globalConfig.removeQuoteBasketUrl)
                .success(function (resp) {
                    location.reload();
                });
        }

        function serializedData(data) {
            if (data != null) {
                if (data.lineItems != null) {
                    angular.forEach(data.lineItems, function (line) {
                        if (isJSON(line.customInfo2)) {
                            line.customInfo2 = JSON.parse(line.customInfo2);
                            line.parentProductId = line.customInfo2.ParentProductId;
                        }
                    });
                }
            }
            return data;
        }

        function formReset(form) {
            if (form) {
                form.$setPristine();
                form.$setUntouched();
            }
        }

        function initLookbooks(data) {
            gm.model = data;
            gm.allLooks = angular.copy(data);
        }

        function fetchLookbookByGroup() {
            if (gm.selectedGroup != undefined && gm.selectedGroup != '' && gm.selectedGroup != null) {
                if (gm.selectedGroup == "All") {
                    gm.model.DynamicLists = gm.allLooks.DynamicLists;
                } else {
                    //gm.model.DynamicLists = gm.allLooks.DynamicLists.filter(i => i.DisplayGroupName == gm.selectedGroup);
                    angular.forEach(gm.allLooks.DynamicLists, function (list) {
                        if (list.DisplayGroupName == gm.selectedGroup) {
                            gm.model.DynamicLists.push(list);
                        }
                    });
                }

            }

        }

        function updateBasketQty(productId, newQty, oldQty, displayOrder) {
            gm.updateQty = 0;
            if (newQty == oldQty || !oldQty) {
                return gm.basketResponse;
            } else {
                if (newQty > oldQty) {
                    gm.updateQty = newQty - oldQty;
                } else {
                    gm.updateQty = -(oldQty - newQty);
                }
                gm.addToBasket(productId, gm.updateQty, displayOrder);
            }
        }

        function getRecommendations() {
            Recommendation.getRecommendation().then(function (resp) {
                if (resp) {
                    gm.recomendations.products = resp;
                    $("#bubbleOption").modal();
                }
            });
        }

        function getAllcurrencyandCountries() {
            $http.post(globalConfig.getAllcurrencySetting)
                .success(function (data) {
                    if (data) {
                        gm.currencies = data.currencies;
                        gm.countries = data.countries;
                    }
                })
                .error(function (msg) {
                })
                .finally(function () {
                });
        };

        function openGiftModal() {
            $(".gift-wrap-itm input.greetingCardsItems").prop("checked", false);
            $(".gift-wrap-modal .step-1").show();
            $(".gift-wrap-modal .step-2").hide();
            $(".personalise-ribbon").show();
            $(".gift-wrap-modal .step-3").hide();
            $(".gift-wrap-modal .step-1 button").text("Continue");

            // Enabled button toggle
            $(".gift-wrap-modal .inr .step-1 .btn-primary").attr("disabled", "disabled").css({ "background-color": "#CCC", "border-color": "#CCC" });
            $(".gift-wrap-modal .gift-wrap-itm input").click(function () {
                if ($(this).is(":checked")) {
                    $(".customise-modal .inr .step-1 .btn-primary").removeAttr("disabled").css({ "background-color": "#1d1258", "border-color": "#1d1258" });
                }
            });

            // Clear ribbon info
            $scope.tsCsChecked = false;
            $scope.personaliseRibbon = "";

            $(".tfs-lds-ring").hide();
            //if (isSelected) {
            $(".gift-wrap-modal").show();
            $(".gift-wrap-modal .close-personalisation").click(function (e) {
                $(".gift-wrap-modal .step-3").hide();
                $(".gift-wrap-modal .personalise-ribbon").show();
                $(".gift-wrap-modal .step-2 button").show();
            });
            $(".gift-wrap-modal .ts-cs a").click(function (e) {
                e.preventDefault();
                $(".gift-wrap-modal .close").hide();
                $(".gift-wrap-modal .step-2").hide();
                $(".gift-wrap-modal .ts-cs-overlay").show();
                $(".ts-cs-overlay .close-ts-cs").click(function () {
                    $(".ts-cs-overlay").hide();
                    $(".gift-wrap-modal .step-2").show();
                    $(".gift-wrap-modal .close").show();
                });
            });
            //}
        }

        // Back gift wrap modal
        function backGiftWrapModal() {
            $(".gift-wrap-modal .step-1").show();
            $(".gift-wrap-modal .step-2").hide();
            gm.addGiftButtonClicked = false;
        }

        // Close gift wrap modal
        function closeGiftWrapModal() {
            $(".gift-wrap-modal").hide();
            $('input#gifts').prop('checked', false);
            $("html").css("overflow-y", "auto");
            $(".gift-wrap-modal .step-1").show();
            $(".gift-wrap-modal .step-2").hide();
            //$(".greeting-card-modal .gift-wrap-itm").remove();
        }

        function editGiftModal() {

        }

        function saveRibbon() {

        }

        function extractSubscription() {
            if (gm.basketResponse != null && gm.basketResponse != undefined && gm.basketResponse.lineItems.length > 0) {
                //extract subscription plan
                var subscriptionItem = '';
                //var subscriptionItem = gm.basketResponse.lineItems.find(i => i.subscriptionUserSettings.subscriptionPlanId != gm.emptyGuid);
                angular.forEach(gm.basketResponse.lineItems, function (item) {
                    if (item.subscriptionUserSettings.subscriptionPlanId != gm.emptyGuid) {
                        subscriptionItem = item;
                    }
                });
                if (subscriptionItem != undefined && subscriptionItem != null && subscriptionItem != '') {
                    gm.subscriptionPlan = JSON.parse(subscriptionItem.subscriptionUserSettings.subscriptionJson);
                    var subscriptionItems = [];
                    if (gm.basketResponse != null && gm.basketResponse != undefined && gm.basketResponse.lineItems.length > 0) {
                        angular.forEach(gm.basketResponse.lineItems, function (item) {
                            if (item.subscriptionUserSettings.subscriptionPlanId == gm.subscriptionPlan.RecordId) {
                                subscriptionItems.push(item);
                            }
                        });
                    }
                    //sort items by thier display order.
                    var sortedItems = subscriptionItems.sort(function (i, j) {
                        return i.displayOrder - j.displayOrder
                    });
                    gm.subscriptionItems = sortedItems;
                } else {
                    gm.subscriptionItems = [];
                }
            } else {
                gm.subscriptionItems = [];
            }

        }


        //Personalisation Section Starts
        function applyPersonalisation(product) {
            gm.engravingSubmitInProgress = true;
            if (product != null && product != undefined) {
                var basketId = '';
                if (gm.basketResponse)
                    basketId = gm.basketResponse.id;
                var engravingModel = {
                    basketId: basketId,
                    productId: product.recordId,
                    stockCode: product.stockCode,
                    Qty: 1,
                    engravingProductId: product.engravingAttributes.productId,
                    engravingStockCode: product.engravingAttributes.stockCode,
                    engravingLines: gm.engravingMsg,
                    engravingColour: gm.engravingColour,
                    engravingAttributes: product.engravingAttributes
                };
                $http.post("/TFSBasket/ApplyPersonalisation", { model: engravingModel }).then(function (success) {
                    if (success != null && success.data != null) {
                        savePersonalisationInfo(success.data, engravingModel);
                    } else {
                        gm.engravingSubmitInProgress = false;
                    }
                }, function (error) {
                    gm.engravingSubmitInProgress = false;
                });
            }
        }

        function savePersonalisationInfo(data, model) {
            if (data) {
                var engravingLineItem = data.result.lineItems.filter(function (itm) {
                    return (itm.parentProductId.toLowerCase() === model.productId.toLowerCase() && itm.productId.toLowerCase() === model.engravingProductId.toLowerCase());
                });
                if (engravingLineItem && engravingLineItem.length > 0) {
                    $http.post("/TFSBasket/SavePersonalisationInfo",
                        {
                            basketId: data.result.id,
                            basketLineModel: engravingLineItem[0],
                            model: model
                        }).then(function (success) {
                            $("#Engraving").modal('hide');
                            //assign updated basket. 
                            updateBasket(success.data);
                            //redirect to offer page
                            redirectToOffers(model.productId, false);
                        },
                            function (error) {
                                gm.basketResponse = data.result;
                                gm.engravingProduct = data.result.lineItems.find(e => e.productId.toLowerCase() === model.productId.toLowerCase());
                                //engraving couldn't be saved. Remove from basket
                                gm.addToBasket(gm.engravingProduct.productId, 0, gm.engravingProduct.displayOrder);
                            });
                } else {
                    gm.basketResponse = data.result;
                    gm.engravingProduct = data.result.lineItems.find(e => e.productId.toLowerCase() === model.productId.toLowerCase());
                    gm.addToBasket(gm.engravingProduct.productId, 0, gm.engravingProduct.displayOrder);
                }
            }
        }

        function engravingFiledActions() {
            $('#Engraving').modal('hide');
            $('#engraving-failed').modal('show').on('hide.bs.modal', function () {
                $("#engraving-failed").off('hide.bs.modal');
                // engraving failed modal closed
                if (gm.engravingFailedAction === 'again') { // user wants to try again
                    $('#Engraving').modal('show');
                    gm.engravingFailedAction = 'remove';
                } else if (gm.engravingFailedAction === 'continue') { // user wants to continue without engraving
                    gm.addToBasket(gm.engravingProduct.productId, 1, 0);
                } else { //none of the above. Close the modal and cancel engraving
                    gm.engravingProduct = null;
                }
                gm.engravingSubmitInProgress = false;
            });
        }


        function closeEngravingFailedModal() {
            $('#engraving-failed').modal('hide');
        }

        function range(length) {
            if (length > 0) {
                return new Array(length);
            }
        }

        function editPersonalisation(item) {
            if (item.customInfo1 != null && item.customInfo1 != undefined && item.customInfo1 != '') {
                var isValid = true;
                var regex = new RegExp(REGEX_CONSTANTS.LETTERS_AND_NUMBERS_ONLY);
                angular.forEach(item.customInfo1.personalisation, function (lines) {
                    if (!regex.test(lines.lines.join(''))) {
                        isValid = false;
                    }
                });
                if (isValid) {
                    var model = {
                        basketId: gm.basketResponse.id,
                        LineInfo: [{
                            productId: item.productId,
                            parentProductId: item.parentProductId,
                            stockCode: item.stockCode,
                            customInfo1: JSON.stringify(item.customInfo1)
                        }]
                    }
                    $http.post("/TFSBasket/UpdatePersonalisationInfo", { customInfo: model }).then(function (success) {
                        updateBasket(success.data);
                        gm.editMsg = false;
                    }, function (error) {
                    });
                } else {
                    gm.regexError = true;
                    $timeout(function () {
                        gm.regexError = false;
                    }, 10000);
                }


            }
        }


        //Engraving Section End

        function updateBasket(data) {

            if (data.messageCode == 'C002' && !gm.isProductExist)
                gm.errorMessage = data.message;
            var giftWrapOption = gm.basketResponse ? gm.basketResponse.giftWrapOption : null;
            var greetingCardOption = gm.basketResponse ? gm.basketResponse.greetingCardOption : null;

            //check if we already have memebrship benefits availabe. reuse them if we do
            let currentBenefits = null;
            if (gm.basketResponse != null && gm.basketResponse.membershipBenefits != null && gm.basketResponse.membershipBenefits.length > 0) {
                currentBenefits = gm.basketResponse.membershipBenefits;
            }

            gm.basketResponse = data.result;
            //reasign benefits
            gm.basketResponse.membershipBenefits = currentBenefits;

            //reset giftwarp options
            if (giftWrapOption && data.result.giftWrapOption === null) {
                gm.basketResponse.giftWrapOption = giftWrapOption;
            }
            //reset greetingcard options
            if (greetingCardOption && data.result.greetingCardOption === null) {
                gm.basketResponse.greetingCardOption = greetingCardOption;
            }
            //var count = 0;
            if (gm.basketResponse != null) {
                if (gm.basketResponse.membershipBenefits != null && gm.basketResponse.membershipBenefits.length > 0 && gm.basketResponse.subTotal != null) {
                    gm.membershipDiscountAmt = gm.selectedCurrencySymbol + ((gm.basketResponse.membershipBenefits[0].discountPct / 100) * gm.basketResponse.subTotal.raw.withTax).toFixed(2);
                }
                if (gm.basketResponse.lineItems != null) {
                    //var eventData = { product: {}, basket: { id: null, lines: [], totalCost: null, totalItems: null, tax: null } };
                    //eventData.id = gm.basketResponse.id;
                    //eventData.basket.totalItems = gm.basketResponse.lineItemCount;
                    //eventData.basket.totalCost = gm.basketResponse.subTotal.raw.withoutTax;
                    //eventData.basket.tax = gm.basketResponse.grandTotal.raw.tax;
                    angular.forEach(gm.basketResponse.lineItems, function (line) {
                        //var li = { id: line.id, basketId: gm.basketResponse.id, stockCode: line.stockCode, name: line.name, qty: line.qty, price: line.price.raw.withoutTax, tax: line.price.raw.tax, manufacturer: line.Manufacture, 'img': line.image };
                        //eventData.basket.lines.push(li);
                        //if (line.parentProductId == gm.emptyGuid) {
                        //    count = count + line.qty;
                        //}
                        if (line.isGiftWrapApplied) {
                            line.giftWrappingInfo = [];
                            //line.giftWrappingInfo = gm.basketResponse.giftWrapOption.filter(x => x.id == line.giftWrapId.toUpperCase());
                            angular.forEach(gm.basketResponse.giftWrapOption, function (opt) {
                                if (opt.id.toUpperCase() == line.giftWrapId.toUpperCase()) {
                                    line.giftWrappingInfo.push(opt);
                                }
                            });
                        }
                        if (line.isGreetingCardApplied) {
                            line.greetingCardInfo = [];
                            //line.greetingCardInfo = gm.basketResponse.greetingCardOption.filter(x => x.id == line.greetingCardId.toUpperCase());
                            angular.forEach(gm.basketResponse.greetingCardOption, function (opt) {
                                if (opt.id.toUpperCase() == line.greetingCardId.toUpperCase()) {
                                    line.greetingCardInfo.push(opt);
                                }
                            });
                        }
                        line.updatedqty = line.qty;
                        //var json = eval('(' + line.attributesJson + ')');
                        //line.slug = json.Slug;
                        //if (line.productId.toLowerCase() == prod.productId.toLowerCase()) {
                        //    var prodDetail = angular.copy(line);
                        //    prodDetail.qty = qty /// set the actual qty that was requested to be aded instead of final  item qty
                        //    prodDetail.basketId = basketId;
                        //    //eventData.product = prodDetail;
                        //}

                    });
                    extractCustomInfo(gm.basketResponse);
                    extractSubscription();
                    initGreetingCards();
                    initRibbons();
                    membershipDiscountPrice();

                    if (isShipFromStoreEnabled() && gm.count > 0) {
                        //add shipfromstore prop
                        lineItemsAddPropShipFromStore();
                    }
                }
                gm.count = gm.basketResponse.lineItemCount;
                if (gm.count > 0) {
                    $(".basketItemCount").removeClass('tfs-bag-badge-hidden').html(gm.count);
                } else {
                    $(".basketItemCount").addClass('tfs-bag-badge-hidden').html(0);
                }

                //paypal messaging refresh
                renderPaypalMessaging();

                //clearpay messaging render
                renderClearpayMessaging();

                //zip messaging
                renderZipMessaging((gm.basketResponse && gm.basketResponse.totalWithoutShipping) ? gm.basketResponse.totalWithoutShipping.raw.withTax : 0);

                //update the min basket badge dynamically
                //var basketCountElem = document.getElementById('headerBasketCountBadge');
                //if (basketCountElem != null && basketCountElem != undefined) {
                // document.getElementById('headerBasketCountBadge').innerHTML = gm.count;
                // }

                //window.setTimeout(function () { imgix.init({ force: true }); }, 1000);
            }
            window.setTimeout(function () {
                gm.errorMessage = null;
            }, 10000);

            if (true) {
                var scroll = $(window).scrollTop();
                if (scroll >= 200) {
                    $("#miniBasket").addClass("fix-to-top");
                } else {
                    $('.cartopen').addClass('active');
                    $("#miniBasket").removeClass("fix-to-top");
                }
                //$("html, body").animate({ scrollTop: 0 }, "slow");
                $('.cartopen').addClass('active');
                $timeout(function () {
                    $(".cartopen").removeClass("active");
                }, 10000);
            }
            //PubSub.publish("addToCart", eventData);

        }

        function updateBasketBadgeCount() {
            if (gm.basketResponse != null && gm.basketResponse != undefined) {
                if (gm.basketResponse.lineItemCount > 0) {
                    $(".basketItemCount").removeClass('tfs-bag-badge-hidden').html(gm.basketResponse.lineItemCount);
                } else {
                    $(".basketItemCount").addClass('tfs-bag-badge-hidden').html(0);
                }
            }

        }

        //Method to Remove Engraving
        function removePersonalisation(product, index) {
            if (product != null) {
                gm.qtyToRemove = 0;
                if (product.qty > 1 && product.customInfo1 != null) {
                    gm.qtyToRemove = -1;
                    product.customInfo1.personalisation.splice(index, 1);
                }
                var basketModel = {
                    basketId: gm.basketResponse.id,
                    productId: product.productId.toLowerCase(),
                    stockCode: product.stockCode,
                    qty: gm.qtyToRemove,
                    parentProductId: product.parentProductId.toLowerCase(),
                    itemType: product.itemType,
                    customInfo1: JSON.stringify(product.customInfo1)
                }
                $http.post(globalConfig.removePersonalisation, { model: basketModel }).then(function (success) {
                    if (success != null && success.data != null)
                        removePersonalisationInfo(success.data.result.id, basketModel)
                }, function (error) {
                });
            }
        }

        function removePersonalisationInfo(basketId, model) {
            if (basketId != null && model != null) {
                $http.post("/TFSBasket/RemovePersonalisationInfo", {
                    basketId: basketId,
                    model: model
                }).then(function (success) {
                    updateBasket(success.data);
                    gm.editMsg = false;
                }, function (error) {
                });
            }
        }

        //Add gift warpping
        function addGiftWrap(selectedGiftOption) {
            if (!gm.addGiftButtonClicked && selectedGiftOption != null && Object.keys(selectedGiftOption) != 0) {
                if (gm.addonsActionPending) return;
                gm.addonsActionPending = true;
                $(".gift-wrap-modal .inr").append("<div class='tfs-lds-ring'><div></div><div></div><div></div><div></div></div>");
                gm.addGiftButtonClicked = true;
                var model = {
                    basketId: gm.basketResponse.id,
                    productId: selectedGiftOption.productId,
                    stockCode: selectedGiftOption.stockCode,
                    Qty: 1,
                    isGiftWrapApplied: true,
                    giftWrapId: selectedGiftOption.id,
                    parentProductId: gm.selectedLineItem.productId,
                };
                $http.post("/Basket/AddGiftWrap", { model: model }).then(function (success) {
                    gm.selectedGiftWrapOption = {};
                    //assign updated basket. 
                    updateBasket(success.data);
                    gm.addGiftButtonClicked = false;
                    gm.addonsActionPending = false;
                    gm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                    gm.changeBaseCurrency(gm.currencyCookie, false);
                    if ($scope.personaliseRibbon.length === 0) {
                        $(".gift-wrap-modal").hide();
                        $(".gift-wrap-modal .inr .tfs-lds-ring").remove();
                    }

                    // add ribbon after gift wrap
                    gm.selectedLineItem.giftWrapId = selectedGiftOption.id;
                    gm.selectedLineItem.isGiftWrapApplied = true;
                    if ($scope.personaliseRibbon.length > 0) {
                        //set seletced ribbon to correct option based on gift wrap
                        const relatedRibbon = findRelatedRibbon(selectedGiftOption.productId);
                        if (!relatedRibbon) {
                            //couldn't find related ribbon
                            //show error
                            return false;
                        };
                        addRibbon(relatedRibbon);
                    }
                }, function (error) {
                    gm.closeGiftWrapModal();
                    gm.giftWrapError = true;
                    gm.addGiftButtonClicked = false;
                    gm.addonsActionPending = false;
                });
            } else {
                gm.giftWrapError = true;
                gm.addGiftButtonClicked = false;
                gm.addonsActionPending = false;
                $timeout(function () {
                    gm.giftWrapError = false;
                }, 10000);
            }
        }

        function giftWrapRibbonPrice(giftWrap) {
            let price = giftWrap.price.raw.withTax;
            const ribbon = getAppliedRibbon(giftWrap.parentProductId);
            //we need to check if the ribbon is applied or not
            //if ribbon is not return just the gift wrap price
            if (!ribbon) return numberToFixed(price);
            //we have a ribbon and need to return it's price added to gift wrap
            price = giftWrap.price.raw.withTax + ribbon.price.raw.withTax;
            return numberToFixed(price);
        }

        function numberToFixed(number) {
            if (typeof number !== 'number') return 0.00;
            return Number(number).toFixed(2);
        }

        function getAppliedRibbon(giftWrapParentProductId) {
            const lineItems = gm.basketResponse['lineItems'];
            if (lineItems.length === 0) return false;
            //find the ribbon wiht the same parentProductId & customInfo3.text property
            const ribbon = lineItems.find(o => o['parentProductId'].toLowerCase() === giftWrapParentProductId.toLowerCase() && o['customInfo3'].hasOwnProperty('text'));
            //return true if we have the ribbon
            if (!ribbon) return null;
            return ribbon;
        }

        function findRelatedRibbon(giftWrapProductId) {
            return gm.ribbbonOptions.find(option => {
                if (option['relatedProducts'].length === 0) return false;
                //we need to check for each ralated product to find the correct match
                return option['relatedProducts'].find(p => {
                    return p['productId'].toLowerCase() === giftWrapProductId.toLowerCase();
                });
            });
        }

        function addGiftWrapSelected(selectedGiftWrap) {
            gm.selectedGiftWrapOption = selectedGiftWrap;
            const relatedRibbon = findRelatedRibbon(selectedGiftWrap.productId);
            if (!relatedRibbon) {
                $(".gift-wrap-modal .step-1 button").text("Add gift wrap");
            } else {
                $(".gift-wrap-modal .step-1 button").text("Continue");
            }
        }

        //Add personalised ribbon
        function addPersonalisedRibbon(selectedGiftOption) {
            const relatedRibbon = findRelatedRibbon(selectedGiftOption.productId);
            if (!relatedRibbon) {
                //couldn't find related ribbon
                //show error
                addGiftWrap(selectedGiftOption);
            } else {
                $(".gift-wrap-modal .step-1").hide();
                $(".gift-wrap-modal .step-2").show();
                gm.selectedRibbonOption = relatedRibbon;
            }

            /* $.ajax({
                url: "/basket/get-ribbons",
                type: "GET",
                beforeSend: function (xhr) {
                    $(".greeting-card-modal .inr").append("<div class='loading-overlay'><img src='/assets/theme/tfs/images/loader.svg' /></div>")
                },
                success: function (data) {
                    $scope.$apply(function () {
                        data = JSON.parse(data);
                        $(".loading-overlay").remove();
                    });
                },
                complete: function () {
                },
                dataType: "html"
            }); */
        }

        function addPersonalisedRibbonForm() {
            $(".gift-wrap-modal .step-3").show();
            $(".gift-wrap-modal .step-2 button").hide();
            $(".gift-wrap-modal .step-2 .step-3 button").show();
            $(".gift-wrap-modal .personalise-ribbon").hide();
        }

        //Remove gift wrapping
        function removeGiftWrap(selectedGiftOption) {
            if (selectedGiftOption != null) {
                let loaderDiv = "<div class='tfs-lds-ring'><div></div><div></div><div></div><div></div></div>";
                gm.apiPendingTfs = true;
                var model = {
                    basketId: gm.basketResponse.id,
                    productId: selectedGiftOption.productId,
                    stockCode: selectedGiftOption.stockCode,
                    Qty: 0,
                    isGiftWrapApplied: false,
                    giftWrapId: selectedGiftOption.id,
                    parentProductId: gm.selectedLineItem.productId,
                    itemType: selectedGiftOption.itemType
                }
                $http.post("/Basket/RemoveGiftWrap", { model: model }).then(function (success) {
                    $("#giftChoose").modal('hide');
                    gm.apiPendingTfs = false;
                    gm.selectedGiftWrapOption = {};
                    //assign updated basket.
                    updateBasket(success.data);
                    gm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                    gm.changeBaseCurrency(gm.currencyCookie, false);
                    isGiftWrapApplied: false;
                    //$(".ribbon-info").addClass("hidden");
                    // Show in basket
                    $(".gift-wrap-modal .step-1").show();
                    $(".gift-wrap-modal .step-2").hide();

                    gm.selectedLineItem.giftWrapId = gm.emptyGuid;
                    gm.selectedLineItem.isGiftWrapApplied = false;

                    //set seletced ribbon to correct option based on gift wrap
                    const relatedRibbon = findRelatedRibbon(selectedGiftOption.productId);
                    if (!relatedRibbon) {
                        //couldn't find related ribbon
                        //show error
                        return false;
                    };

                    removeRibbon(relatedRibbon);
                }, function (error) {
                    gm.apiPendingTfs = false;
                });
            } else {
                //give error msg.
            }
        }

        //Handle closed gift dialog when no options were selected
        function checkGiftWrap() {
            if (gm.addGiftButtonClicked === false) {
                $scope.$apply(function () {
                    angular.forEach(gm.basketResponse.lineItems, function (line) {
                        line.giftWrappingInfo = [];
                        angular.forEach(gm.basketResponse.giftWrapOption, function (opt) {
                            if (opt.id.toUpperCase() == line.giftWrapId.toUpperCase()) {
                                line.giftWrappingInfo.push(opt);
                            }
                        });
                        line.updatedqty = line.qty;
                        line.isGiftWrapApplied = line.giftWrappingInfo.length > 0;
                    });
                });
            }
        }

        function unsubscribedNewsletter() {
            $http.post(globalConfig.unsubscribeNewsletter)
                .success(function (data) {
                    gm.errorMessage = null;
                    gm.isValid = data.isValid;
                    gm.isValiduser = !data.isValid;
                    gm.unsubssuccess = true;
                    $('.newsletterunsuccess').show(0).delay(2000).hide(0);
                    $timeout(function () {
                        gm.isValiduser = false;
                        gm.isValid = false;
                        window.location.reload();
                    }, 3000);
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                    $timeout(function () {
                        gm.isValiduser = false;
                        $(".alertBlock").fadeOut();
                    }, 2000);
                })
                .finally(function () {
                });
        };
        gm.showChangedCurrency = false;
        function changeBaseCurrency(changeToCurrencyCode, doReload) {
            if (gm.enableChangeBaseCurrencyV2 == 1 && doReload) {
                changeBaseCurrencyV2(changeToCurrencyCode);
            }
            else if (gm.enableChangeBaseCurrencyV2 != 1) {
                if ($.cookie('basecurrencyv2'))
                    $.removeCookie('basecurrencyv2', { path: '/' });
                if (changeToCurrencyCode == null) {
                    changeToCurrencyCode = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                }
                if (changeToCurrencyCode) {
                    $http.get('/Home/GetCurrencyExchangeRate' + "?changeToCurrencyCode=" + changeToCurrencyCode).then(function (resp) {
                        if (resp != null && resp.data != false && resp.data.rate != 1) {
                            gm.showChangedCurrency = true;
                            gm.selectedCurrencySymbol = resp.data.currencySymbol;
                            gm.defaultCurrency = resp.data.currencySymbol;
                            gm.currencyExchangeRate = resp.data.resp;

                            // Discount amount if not a member/logged in
                            if (gm.basketResponse.membershipBenefits == null) {
                                gm.membershipDiscountAmt = gm.selectedCurrencySymbol + ((gm.basketResponse.subTotal.raw.withTax / 100) * 20 * resp.data.rate).toFixed(2);
                            }

                            // Saving amount if active membership
                            if (gm.basketResponse != null && gm.basketResponse.membershipBenefits != null && gm.basketResponse.membershipBenefits.length > 0) {
                                var membershipProductAmount = 0;
                                angular.forEach(gm.basketResponse.lineItems, function (line) {
                                    if (line.isMembership)
                                        membershipProductAmount = membershipProductAmount + line.price.raw.withTax;
                                });
                                gm.membershipDiscountAmt = gm.selectedCurrencySymbol + ((gm.basketResponse.membershipBenefits[0].discountPct / 100) * (gm.basketResponse.subTotal.raw.withTax - membershipProductAmount) * resp.data.rate).toFixed(2);
                            }

                            // Saving amount on Membership landing page
                            gm.potentialSavings = gm.selectedCurrencySymbol + (gm.basketResponse.grandTotal.raw.withTax * 0.2 * resp.data.rate).toFixed(2);

                            if (gm.basketResponse != null && gm.basketResponse.lineItems) {
                                angular.forEach(gm.basketResponse.lineItems, function (item) {
                                    item.currencyExchangedPriceRaw = item.price.raw.withTax * resp.data.rate;
                                    item.currencyExchangedPriceFormatted = gm.selectedCurrencySymbol + item.currencyExchangedPriceRaw.toFixed(2);
                                    if (item.isGiftWrapApplied && item.giftWrappingInfo.length > 0)
                                        item.currencyExchangedItemGiftWrapPrice = gm.selectedCurrencySymbol + (item.giftWrappingInfo[0].price.raw.withoutTax * resp.data.rate).toFixed(2);
                                    if (item.isGreetingCardApplied && item.greetingCardInfo.length > 0)
                                        item.currencyExchangedItemGreetingCardPrice = gm.selectedCurrencySymbol + (item.greetingCardInfo[0].price.raw.withoutTax * resp.data.rate).toFixed(2);
                                });
                                angular.forEach(gm.basketResponse.promotionsApplied, function (promo) {
                                    promo.currencyExchangedDiscountAmt = gm.selectedCurrencySymbol + (promo.discountAmt.raw.withoutTax * resp.data.rate).toFixed(2);
                                });
                                if (gm.basketResponse.giftWrapOption) {
                                    angular.forEach(gm.basketResponse.giftWrapOption, function (gift) {
                                        gift.currencyExchangeGiftWrapPrice = gm.selectedCurrencySymbol + (gift.price.raw.withoutTax * resp.data.rate).toFixed(2);
                                    });
                                }
                                if (gm.basketResponse.greetingCardOption) {
                                    angular.forEach(gm.basketResponse.greetingCardption, function (card) {
                                        card.currencyExchangeGreetingCardPrice = gm.selectedCurrencySymbol + (card.price.raw.withoutTax * resp.data.rate).toFixed(2);
                                    });
                                }
                                gm.currencyExchangedSubtotalFormatted = gm.selectedCurrencySymbol + (gm.basketResponse.subTotal.raw.withTax * resp.data.rate).toFixed(2);
                                gm.currencyExchangedtotalWithoutShippingFormatted = gm.selectedCurrencySymbol + (gm.basketResponse.totalWithoutShipping.raw.withTax * resp.data.rate).toFixed(2);
                            }
                        }
                        else
                            gm.showChangedCurrency = false;
                        if (changeToCurrencyCode != $.cookie(CURRENCYCOOKIE.CurrencyCode)) {
                            $.cookie("_ctcc", changeToCurrencyCode, { path: '/', expires: 1000 });
                        }
                        if (doReload) {
                            window.location.reload();
                        }
                    }, function (error) {
                    });
                }
            }
        };
        function showCurrencyPopUp() {
            $("#currency-modal").modal();
        }

        function setCookie(cookieName, value) {
            var now = new Date();
            var exp = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
            $.cookie(cookieName, value, { path: '/', expires: exp });
        }
        function addSampleLookbookToCart(data) {
            var isAlreadyExistInBasket = false;
            $http.post(globalConfig.bulkAddproduct, data)
                .success(function (data) {
                    var dataResult = gm.serializedData(data.result);
                    if (data.messageCode == 'C002') {
                        gm.errorMessage = data.message;
                        $('.alert').show(0).delay(4000).hide(0);
                    }
                    gm.basketResponse = dataResult;
                    PubSub.publish("addToCartBulk", gm.basketResponse);
                    var count = 0;
                    if (gm.basketResponse != null) {
                        if (gm.basketResponse.lineItems != null) {
                            angular.forEach(gm.basketResponse.lineItems, function (line) {
                                if (line.parentProductId == gm.emptyGuid) {
                                    count = count + line.qty;
                                }
                                var json = eval('(' + line.attributesJson + ')');
                                line.slug = json.Slug;
                                isAlreadyExistInBasket = false;
                            });
                            gm.count = gm.basketResponse.lineItemCount;
                        }
                    }
                    redirectToOffers(gm.basketResponse.id, isAlreadyExistInBasket);
                }).error(function () {
                    gm.wrongFormatMessage = true;
                    $('.wrongFormatError').show(0).delay(3000).hide(0);
                });
        }

        gm.hasMembership = globalConfig.hasMembership;
        function initMembershipPlans(data) {
            gm.membershipList = data;
            // harcode the number of vouchers per Tier :-(
            // TODO: this need to be populated from the API!!!
            angular.forEach(gm.membershipList, function (benefit) {
                if (benefit['stockCode'] === "53241") {
                    benefit['voucherCount'] = 3;
                    benefit['voucherImg'] = "https://the-fragrance-shop.imgix.net/UX/content/membership/my-tfs-logo-sparkle.svg";
                }
                if (benefit['stockCode'] === "53221") {
                    benefit['voucherCount'] = 5;
                    benefit['voucherImg'] = "https://the-fragrance-shop.imgix.net/UX/content/membership/my-tfs-plus-logo-sparkle.svg";
                }
                if (benefit['stockCode'] === "53222") {
                    benefit['voucherCount'] = "UNLIMITED";
                    benefit['voucherImg'] = "https://the-fragrance-shop.imgix.net/UX/content/membership/my-tfs-family-logo-sparkle.svg";
                }
            });
        }

        gm.unClaimedMembershipVouchers = [];
        gm.membershipDiscountAmt = 0;
        gm.membershipDiscountPercentage = 0;
        function getUnClaimedVouchers() {
            gm.checkVoucherApplied();
            if (gm.basketResponse != null && gm.basketResponse.membershipBenefits != null && gm.basketResponse.membershipBenefits.length > 0) {
                angular.forEach(gm.basketResponse.membershipBenefits, function (benefit) {
                    if (
                        (typeof benefit.status === 'string' && benefit.status.toLowerCase() == VOUCHERSTATUS.UNCLAIMED.toLowerCase()) ||
                        (typeof benefit.status === 'string' && benefit.status.toLowerCase() == VOUCHERSTATUS.IN_TRANSITION.toLowerCase() && gm.basketResponse.isMembershipUpgrade)
                    ) {
                        gm.unClaimedMembershipVouchers.push(benefit);
                    }
                    if (benefit.voucher.toLowerCase() == gm.deletedPromoCode.toLowerCase()) {
                        benefit.status = VOUCHERSTATUS.UNCLAIMED;
                        gm.membershipVoucherApplied = false;
                        gm.unClaimedMembershipVouchers.push(benefit);
                    }
                });

                gm.deletedPromoCode = '';
                gm.activeMemebershipPlanId = angular.copy(gm.basketResponse.membershipBenefits[0].siteUserMembershipId);
                var membershipProductAmount = 0;
                angular.forEach(gm.basketResponse.lineItems, function (line) {
                    if (line.isMembership)
                        membershipProductAmount = membershipProductAmount + line.price.raw.withTax;
                });
                gm.membershipDiscountAmt = gm.selectedCurrencySymbol + ((gm.basketResponse.membershipBenefits[0].discountPct / 100) * (gm.basketResponse.subTotal.raw.withTax - membershipProductAmount)).toFixed(2);
                gm.membershipDiscountPercentage = gm.basketResponse.membershipBenefits[0].discountPct;
            }
        }

        gm.isMembershipUpgradeAvailable = isMembershipUpgradeAvailable;
        function isMembershipUpgradeAvailable() {
            if (typeof enableMembershipUpgrade !== 'undefined' && enableMembershipUpgrade === false) return false;
            if (gm.basketContainsMembership) return false;
            if (gm.membershipUpgradeOptions.length === 0) return false;
            return true;
        }

        gm.isMembershipUpgradeAllowed = isMembershipUpgradeAllowed;
        function isMembershipUpgradeAllowed() {
            if (typeof enableMembershipUpgrade !== 'undefined' && enableMembershipUpgrade === false) return false;
            if (gm.membershipUpgradeOptions.length === 0) return false;
            return true;
        }


        if ((gm.isBasketPage || gm.isAccountMembershipPage || gm.isMembershipLandingPage) && typeof enableMembershipUpgrade !== 'undefined' && enableMembershipUpgrade === true) {
            getMembershipUpgradeOptions();
        }

        gm.currentMembershipPlanName = null;
        function getActiveMembershipName() {
            //do not know why it is contianed within each optional upgrade 
            angular.forEach(gm.membershipUpgradeOptions, function (membership) {
                gm.currentMembershipPlanName = membership.upgradeFromMembershipName;
            });
        }

        function addLogosForMembershipUpgradeOptions() {
            if (gm.membershipUpgradeOptions.length == 0) return;
            angular.forEach(gm.membershipUpgradeOptions, function (option) {
                if (option['stockCode'] === "54270") {
                    option['voucherImg'] = "https://the-fragrance-shop.imgix.net/UX/content/membership/my-tfs-plus-logo-sparkle.svg";
                }
                if (option['stockCode'] === "54271" || option['stockCode'] === "54272") {
                    option['noOfVouchers'] = "UNLIMITED";
                    option['voucherImg'] = "https://the-fragrance-shop.imgix.net/UX/content/membership/my-tfs-family-logo-sparkle.svg";
                }
            });
        }

        gm.membershipUpgradeOptions = [];
        gm.membershipUpgradeSelectedOption = null;
        function getMembershipUpgradeOptions() {
            //let's check if member is eligible for upgrade
            $http.get(MEMBERSHIP.URL_UPGRADE_OPTIONS)
                .success(function (res) {
                    if (!res.canUpgrade) return;
                    //we can upgrade. Assign options to global array
                    gm.membershipUpgradeOptions = res.options;
                    addLogosForMembershipUpgradeOptions();
                    getActiveMembershipName();
                })
                .error(function (error) {
                    console.log('Error fetching membership upgrade options.');
                })
                .finally(function () {
                    console.log('Membership upgrade options fetched.');
                });
        }

        function checkVoucherApplied() {
            if (gm.basketResponse != null && gm.basketResponse.promotionsApplied != null && gm.basketResponse.membershipBenefits != null) {
                angular.forEach(gm.basketResponse.promotionsApplied, function (promo) {
                    angular.forEach(gm.basketResponse.membershipBenefits, function (benefit) {
                        if (benefit.voucher.toLowerCase() == promo.promoCode.toLowerCase()) {
                            benefit.status = VOUCHERSTATUS.CLAIMED;
                            gm.membershipVoucherApplied = true;
                        }
                    });
                });
            }
        }

        function applyMembershipVoucher() {
            //check if there is a promo already applied AND its not a membership discount
            if (gm.basketResponse.promotionsApplied.length > 0 && !gm.membershipVoucherApplied) {
                sessionStorage.setItem(gm.applyMembershipVoucherAfterRedirect, true);
                gm.removePromoCode(gm.basketResponse.id, gm.basketResponse.promotionsApplied[0].promoCode);
            } else {
                var promoCode = gm.unClaimedMembershipVouchers[0].voucher;
                gm.unClaimedMembershipVouchers[0].status = VOUCHERSTATUS.CLAIMED;
                gm.applyPromoCode(gm.basketResponse.id, promoCode, true);
            }
        }

        function customError() {
            $timeout(function () {
                $(".alertBlock").fadeOut();
            }, 10000);
        }

        function showMembershipModal(targetLocation) {
            $(".modal-reminder").show();
            const closeMembershipModal = $(".modal-reminder .top .close, .modal-reminder .btn");
            $(closeMembershipModal).click(function () {
                $(".modal-reminder").hide();
            });
            $(".modal-reminder .btm .close").click(function () {
                window.location.href = targetLocation;
            });
        };

        function isOnlyMembershipInTheBasket() {
            return gm.basketResponse.lineItems.every(a => !0 === a.isMembership)
        }

        gm.isOnlySubInTheBasket = isOnlySubInTheBasket;

        function isOnlySubInTheBasket() {
            return gm.basketResponse.lineItems.every(a => !0 === a.isSubscription)
        }


        gm.isOnlyVirtualInTheBasket = isOnlyVirtualInTheBasket;
        function isOnlyVirtualInTheBasket() {
            return gm.basketResponse.lineItems.every(a => a.itemGroupId === 7)
        }

        function hasOnlyMembershipProducts() {
            var membershipLines = [];
            var subLines = [];
            angular.forEach(gm.basketResponse.lineItems, function (line) {
                if (line.isMembership) {
                    membershipLines.push(line);
                }
                if (line.isSubscription) {
                    subLines.push(line);
                }
            });
            return (subLines.length > 0 && membershipLines.length > 0 && gm.basketResponse.lineItems.length == membershipLines.length + subLines.length) ? true : false;
        }

        //THIS IS THE MAIN METHOD WHICH IS NOW USED TO PROCEED TO CHECKOUT
        function proceedToCheckout(e) {
            e.preventDefault();

            //prevent double membership purchases
            var membershipBasket = false;
            if (gm.userHasMembership == 1 && gm.basketResponse != null) {
                angular.forEach(gm.basketResponse.lineItems, function (item) {
                    if (item != null && item.isMembership == true && item.itemType == 2) {
                        membershipBasket = true;
                    }
                });

                if (membershipBasket == true) {
                    $(".membershipBasketErrorMsg").fadeIn();
                    gm.showMembershipBasketErrorMsg = true;
                    $timeout(function () {
                        $(".membershipBasketErrorMsg").fadeOut();
                        gm.showMembershipBasketErrorMsg = false;
                    }, 10000);
                    membershipBasket = false;
                    return;
                }
            }

            //prevent user to proceed to basket if it is not valid
            if (isShipFromStoreEnabled() && !gm.tfsBasketDataValidation.validBasket) {
                shipFromStoreModalShow();
                return;
            }

            //do not allow the checkout if we have a pending API
            if (gm.apiPendingTfs) {
                return;
            }

            const targetLocation = e.target.dataset.href;
            //check if we need to show membershiop modal
            if (typeof enableMembershipOnline !== 'undefined' && enableMembershipOnline === true && gm.unClaimedMembershipVouchers.length > 0 && gm.membershipVoucherApplied === false && !isOnlyMembershipInTheBasket() && !hasOnlyMembershipProducts() && !isOnlySubInTheBasket() && !isOnlyVirtualInTheBasket()) {
                showMembershipModal(targetLocation);
                //check if we have scentaddict redemption in the basket.
                //If true show the old checkout to the user
            } else if (isScentaddictRedemptionBasket()) {
                window.location.href = `/checkout/2/${gm.basketResponse.id}`;
            } else {
                window.location.href = targetLocation;
            }
        }

        function lineItemsAddonsProp() {
            angular.forEach(gm.basketResponse.lineItems, function (item) {
                item['disableGiftWrap'] = gm.tfsBasketDataValidation.disableGiftWrap;
                if (gm.isMultiFulfilmentEnabled) {
                    //check what type deliveryPlan item is on
                    angular.forEach(gm.basketResponse.deliveryPlans, function (dp) {
                        angular.forEach(dp['lineItems'], function (dpi) {
                            if (dpi['productId'].toLowerCase() === item['productId'].toLowerCase() && dp['deliveryCenter']['code'] === 'Warehouse') {
                                item['disableGiftWrap'] = false;
                            }
                        });
                    });
                }
            });
        }

        function lineItemsAddPropShipFromStore() {
            angular.forEach(gm.basketResponse.lineItems, function (item) {
                item['isShipFromStore'] = gm.isShipFromStoreProduct;
                if (gm.isMultiFulfilmentEnabled) {
                    //check what type deliveryPlan item is on
                    angular.forEach(gm.basketResponse.deliveryPlans, function (dp) {
                        angular.forEach(dp['lineItems'], function (dpi) {
                            if (dpi['productId'].toLowerCase() === item['productId'].toLowerCase() && dp['deliveryCenter']['code'] === "PhysicalStore") {
                                item['isShipFromStore'] = true;
                            }
                        });
                    });
                }
            });
        }

        function isShipFromStoreEnabled() {
            return (typeof enableShipFromStore !== 'undefined' && enableShipFromStore === true);
        }

        gm.isMultiFulfilmentEnabled = isMultiFulfilmentEnabled();
        function isMultiFulfilmentEnabled() {
            return (typeof enableMultiFulfilment !== 'undefined' && enableMultiFulfilment === true);
        }

        function isScentaddictRedemptionBasket() {
            return hasScentaddictCouponCode && (gm.subscriptionItems != null && gm.subscriptionItems != undefined && gm.subscriptionItems.length > 0);
        }

        // Greeting Cards
        // Load greeting cards
        function loadGreetingCards() {
            if (greetingCardsLoaded == false && gm.isBasketPage && enableGreetingCards) {
                $.ajax({
                    url: "/basket/get-greeting-cards",
                    type: "GET",
                    beforeSend: function (xhr) {
                        //$(".greeting-card-modal .inr").append("<div class='tfs-lds-ring'><div></div><div></div><div></div><div></div></div>");
                    },
                    success: function (data) {
                        greetingCardsLoaded = true;
                        $scope.$apply(function () {
                            data = JSON.parse(data);
                            if (data.length > 0) {

                                angular.forEach(data, function (card) {
                                    gm.greetingCardOptions.push(card);
                                });
                                //data.forEach(card => {
                                //    gm.greetingCardOptions.
                                //    appendGreetingCards(card)
                                //});
                            }

                            //function appendGreetingCards(cardDetails) {
                            //    const greetingCard = $("<div class='gift-wrap-itm'><div class='lhs'><label ng-click='gm.selectedGreetingCardOption()' class='control control--radio mt-30px m-no-margin-top'><input id='greetingCard' name='greetingCard' type='radio' /><div class='control__indicator__basket'></div></label><img src='https://the-fragrance-shop.imgix.net/product/" + cardDetails.stockCode + "-1.jpg?h=260&w=260&max-w=260" + cardDetails.image + "' /></div><div class='rhs'><p class='name'>" + cardDetails.name + "</p><p class='price'>" + cardDetails.price.formatted.withTax + "</p></div></div>");
                            //    $scope.$apply(function () {
                            //        $(".step-1").prepend(greetingCard);
                            //    });
                            //}
                            $(".loading-overlay").remove();
                        });
                    },
                    complete: function () {
                    },
                    dataType: "html"
                });
            }
        }

        // Open Greeting Card Modal
        function openGreetingCardModal() {
            $(".greeting-card-modal").show();
            if (typeof MagicZoom !== 'undefined') {
                MagicZoom.refresh();
            };
            $(".tfs-lds-ring").hide();
            $("html").css({ "overflow-y": "hidden", "touch-action": "none", "-ms-touch-action": "none" });

            // Enabled button toggle
            $(".customise-modal .inr .step-1 .btn-primary").attr("disabled", "disabled").css({ "background-color": "#CCC", "border-color": "#CCC" });
            $(".greeting-card-modal .gift-wrap-itm input").click(function () {
                if ($(this).is(":checked")) {
                    $(".customise-modal .inr .step-1 .btn-primary").removeAttr("disabled").css({ "background-color": "#1d1258", "border-color": "#1d1258" });
                }
            });

            // Clear greeting card info
            $scope.tsCsChecked = false;
            $scope.greetingCardMessage = "";
            $scope.greetingCardEnvelope = "";

            // Open Ts & Cs
            $(".greeting-card-modal .ts-cs a").click(function (e) {
                e.preventDefault();
                $(".greeting-card-modal .close").hide();
                $(".greeting-card-modal .step-2").hide();
                $(".greeting-card-modal .ts-cs-overlay").show();
                $(".ts-cs-overlay .close-ts-cs").click(function () {
                    $(".ts-cs-overlay").hide();
                    $(".greeting-card-modal .step-2").show();
                    $(".greeting-card-modal .close").show();
                });
            });
        }

        // Close greeting card modal
        function closeGreetingCardModal() {
            $(".greeting-card-modal").hide();
            $('#greetingCard').prop('checked', false);
            $("html").css("overflow-y", "auto");
            $(".greeting-card-modal .step-1").show();
            $(".greeting-card-modal .step-2").hide();
            $(".gift-wrap-itm input.greetingCardsItems").prop("checked", false);
            //$(".greeting-card-modal .gift-wrap-itm").remove();
        }

        // Back greeting card modal
        function backGreetingCardModal() {
            $(".greeting-card-modal .step-1").show();
            $(".greeting-card-modal .step-2").hide();
            gm.addGreetingCardButtonClicked = false;
        }

        // Add greeting card
        function addGreetingCard(selectedCardOption) {
            if (gm.addonsActionPending) return;
            gm.addonsActionPending = true;
            $(".greeting-card-summary").removeClass("hidden");
            $(".greeting-card-item").removeClass("hidden");
            $(".greeting-card-modal .inr").append("<div class='tfs-lds-ring'><div></div><div></div><div></div><div></div></div>");
            $("html").css("overflow-y", "auto");
            //if (!gm.addGreetingCardButtonClicked && selectedCardOption != null && Object.keys(selectedCardOption) != 0) {
            gm.addGreetingCardButtonClicked = true;
            var greetingCardModel = {
                basketId: gm.basketResponse.id,
                parentProductId: gm.selectedLineItem.productId,
                Qty: 1,
                greetingCardId: selectedCardOption.recordId,
                greetingCardStockCode: selectedCardOption.stockCode,
                greetingCardText: $(".greeting-card-modal .step-2 textarea").val(),
                greetingCardEnvelope: $(".greeting-card-modal .step-2 input[type='text']").val()
            };
            $http.post("/basket/add-greeting-card", { model: greetingCardModel, lineItem: gm.selectedLineItem }).then(function (success) {
                gm.addonsActionPending = false;
                gm.selectedGreetingCardOption = {};
                //    //assign updated basket. 
                updateBasket(success.data);
                //    gm.addGreetingCardButtonClicked = false;
                gm.addGreetingCardButtonClicked = false;
                gm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                gm.changeBaseCurrency(gm.currencyCookie, false);
                $(".greeting-card-modal").hide();
                //$(".greeting-card-items").removeClass("hidden");
                $(".greeting-card-modal .inr .tfs-lds-ring").remove();
                // Show in basket
                $(".greeting-card-modal .step-1").show();
                $(".greeting-card-modal .step-2").hide();

                //uncheck radios
                $(".gift-wrap-itm input.greetingCardsItems").prop("checked", false);

                //set greeting card to true
                gm.selectedLineItem.isGreetingCardApplied = true;
            }, function (error) {
                gm.addonsActionPending = false;
            });
            //}
            gm.addGreetingCardButtonClicked = true;
        }

        function addGreetingCardPersonalisation(selectedCard) {
            if (!gm.addGreetingCardButtonClicked && selectedCard != null && Object.keys(selectedCard) != 0) {
                gm.addGreetingCardButtonClicked = true;
                $(".greeting-card-modal .step-1").hide();
                $(".greeting-card-modal .step-2").show();
            } else {
                gm.addGreetingCardButtonClicked = false;
            }
        }

        // Edit greeting card
        function editGreetingCard(target) {
            $(`#summary_${target.productId}_${target.parentProductId}`).hide();
            $(`#form_${target.productId}_${target.parentProductId}`).removeClass("hidden");

            $(".greeting-card-info .form-control").each(function () {
                let inputLimit = $(this).attr("maxlength")
                $(this).on("keyup", function () {
                    $(this).siblings().find(".character-count").text(this.value.length + " / " + inputLimit);
                });
            });
        }

        // Hide greeting card
        function hideGreetingCard(target) {
            $(`#summary_${target.productId}_${target.parentProductId}`).show();
            $(`#form_${target.productId}_${target.parentProductId}`).addClass("hidden");
        }

        // Save edited greeting card
        function saveEditGreetingCard(greetingCard) {

            const greetingCardMessage = $(`#info4_${greetingCard.productId}_${greetingCard.parentProductId}`).val();
            const greetingCardEnvelope = $(`#info5_${greetingCard.productId}_${greetingCard.parentProductId}`).val();

            var model = {
                basketId: gm.basketResponse.id,
                LineInfo: [{
                    productId: greetingCard.productId,
                    parentProductId: greetingCard.parentProductId,
                    stockCode: greetingCard.stockCode,
                    customInfo4: JSON.stringify({ text: greetingCardMessage }),
                    customInfo5: JSON.stringify({ text: greetingCardEnvelope })
                }]
            }

            gm.apiPendingTfs = true;

            $http.post("basket/update-greeting-card", { customInfo: model }).then(function (response) {
                $(`#summary_${greetingCard.productId}_${greetingCard.parentProductId}`).show();
                $(`#form_${greetingCard.productId}_${greetingCard.parentProductId}`).addClass("hidden");
                gm.apiPendingTfs = false;

                updateBasket(response.data);
            }, function (error) {
                gm.apiPendingTfs = false;
            });
        }

        // Remove greeting card
        function removeGreetingCard(greetingCard) {
            var greetingCardModel = {
                basketId: gm.basketResponse.id,
                parentProductId: gm.selectedLineItem.productId,
                Qty: 0,
                greetingCardId: greetingCard.productId,
                greetingCardStockCode: greetingCard.stockCode,
            };
            gm.apiPendingTfs = true;
            $http.post("/basket/remove-greeting-card-info", { model: greetingCardModel, lineItem: gm.selectedLineItem }).then(function (response) {
                updateBasket(response.data);
                gm.apiPendingTfs = false;
            }, function (error) {
                gm.apiPendingTfs = false;
            });
        }

        // Add ribbon
        if (gm.isBasketPage && enableRibbons) {
            getRibbons();
        }

        gm.ribbbonOptions = [];

        function getRibbons() {
            $http.post("basket/get-ribbons").then(function (response) {
                //THIS IS TEMPORARY JUST FETCHING SINGLE RIBBON
                if (response['data'] && response['data'].length > 0) {
                    gm.ribbbonOptions = response['data'];
                }

                //attach ribbions to gift wrap options
            }, function (error) {
            });
        }

        function addRibbon(selectedRibbon) {
            //if (!gm.addGreetingCardButtonClicked && selectedCardOption != null && Object.keys(selectedCardOption) != 0) {
            gm.addGreetingCardButtonClicked = true;
            if (gm.addonsActionPending) return;
            gm.addonsActionPending = true;

            var ribbonModel = {
                basketId: gm.basketResponse.id,
                parentProductId: gm.selectedLineItem.productId,
                Qty: 1,
                ribbonId: selectedRibbon.recordId,
                ribbonStockCode: selectedRibbon.stockCode,
                ribbonText: $(".gift-wrap-modal input.ribbon-text").val(),
            };
            $http.post("/basket/add-ribbon", { model: ribbonModel, lineItem: gm.selectedLineItem }).then(function (success) {
                //    //assign updated basket. 
                updateBasket(success.data);
                //    gm.addGreetingCardButtonClicked = false;
                gm.addRibbonButtonClicked = false;
                gm.addonsActionPending = false;
                gm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                gm.changeBaseCurrency(gm.currencyCookie, false);
                $(".gift-wrap-modal").hide();
                $(".gift-wrap-modal .inr .tfs-lds-ring").remove();
                //$(".greeting-card-items").removeClass("hidden");

                // Show in basket
                $(".gift-wrap-modal .step-1").show();
                $(".gift-wrap-modal .step-2").hide();
            }, function (error) {
                gm.addonsActionPending = false;
            });
            //}
            gm.addRibbonButtonClicked = true;
        }

        function editRibbon(target) {
            $(`#ribbon-summary_${target.productId}_${target.parentProductId}`).addClass("hidden");
            $(`#ribbon-form_${target.productId}_${target.parentProductId}`).removeClass("hidden");

            $(".edit-ribbon .ribbon-controls span").click(function () {
                $(".ribbon-info").removeClass("hidden");
                $(".edit-ribbon.ribbon-info").addClass("hidden");
            });

            $(".edit-ribbon .form-control").each(function () {
                let inputLimit = $(this).attr("maxlength")
                $(this).on("keyup", function () {
                    $(this).siblings().find(".character-count").text(this.value.length + " / " + inputLimit);
                });
            });
        }

        // Update ribbon
        function updateRibbon(ribbon) {

            const personaliseRibbon = $(`#info3_${ribbon.productId}_${ribbon.parentProductId}`).val();

            var model = {
                basketId: gm.basketResponse.id,
                LineInfo: [{
                    productId: ribbon.productId,
                    parentProductId: ribbon.parentProductId,
                    stockCode: ribbon.stockCode,
                    customInfo3: JSON.stringify({ text: personaliseRibbon }),
                }]
            }

            gm.apiPendingTfs = true;

            $http.post("basket/update-ribbon", { customInfo: model }).then(function (response) {
                updateBasket(response.data);
                $(".ribbon-info").removeClass("hidden");
                $(".edit-ribbon.ribbon-info").addClass("hidden");
                gm.apiPendingTfs = false;
            }, function (error) {
                gm.apiPendingTfs = false;
            });
        }

        function removeRibbon(ribbon) {
            var ribbonModel = {
                basketId: gm.basketResponse.id,
                parentProductId: gm.selectedLineItem.productId,
                Qty: 0,
                ribbonId: ribbon.productId,
                ribbonStockCode: ribbon.stockCode,
            };
            gm.apiPendingTfs = true;
            $http.post("/basket/remove-ribbon", { model: ribbonModel, lineItem: gm.selectedLineItem }).then(function (response) {
                updateBasket(response.data);
                gm.apiPendingTfs = false;
            }, function (error) {
                gm.apiPendingTfs = false;
            });
        }

        function initGreetingCards() {
            angular.forEach(gm.basketResponse.lineItems, function (greetingCardLine) {
                if (greetingCardLine.customInfo4 != null) {
                    angular.forEach(gm.basketResponse.lineItems, function (parentLine) {
                        if (parentLine.productId.toUpperCase() == greetingCardLine.parentProductId.toUpperCase() && greetingCardLine.itemType != 7 && greetingCardLine.customInfo1 == '' && greetingCardLine.customInfo4.text) {
                            parentLine.isGreetingCardApplied = true;
                        }
                    });
                }
            });
        }

        function initRibbons() {
            angular.forEach(gm.basketResponse.lineItems, function (ribbonLine) {
                if (ribbonLine.customInfo3 != null) {
                    angular.forEach(gm.basketResponse.lineItems, function (parentLine) {
                        if (parentLine.productId.toUpperCase() == ribbonLine.parentProductId.toUpperCase() && ribbonLine.itemType != 7 && ribbonLine.customInfo1 == '' && ribbonLine.customInfo3.text) {
                            parentLine.isRibbonApplied = true;
                        }
                    });
                }
            });
        }

        function renderPaypalMessaging() {
            if (typeof window.paypal === "undefined" && gm.isBasketPage && typeof payPalClientId === 'string' && enablePayPalMessaging) {
                const ppJs = document.createElement('script');
                ppJs.src = "https://www.paypal.com/sdk/js?components=messages&currency=GBP&client-id=" + payPalClientId;
                document.body.append(ppJs);
            }
        }

        function renderClearpayMessaging() {
            if (typeof window.Afterpay === "undefined" && gm.isBasketPage && typeof enableClearpayMessaging !== "undefined" && enableClearpayMessaging === true) {
                const cpJS = document.createElement('script');
                cpJS.src = "https://js.afterpay.com/afterpay-1.x.js";
                cpJS.dataset.min = "1.00";
                cpJS.dataset.max = "1000.00";
                cpJS.async = true;
                document.body.append(cpJS);
            }
        }

        gm.renderZipMessaging = renderZipMessaging;
        function renderZipMessaging(amount = 0) {
            if (gm.isBasketPage && enableZipMessaging) {
                //add CSS overwrites
                const zipStyles = document.getElementById('zip-styles-head');
                //check is CSS is already attached
                if (!zipStyles) {
                    const css = `#zip-messaging-container #partPayCalculatorWidget {padding: 0;width: 100%;background-color: transparent;display: flex;} #zip-messaging-container #partPayCalculatorWidget #partPayCalculatorWidgetLogo {display: inline; float: unset;order: 1;flex: 0 0 auto;} #zip-messaging-container #partPayCalculatorWidget #partPayCalculatorWidgetLogo img {height: 1.5rem;display: inline-block;margin-top: 0;margin-left: 0.5rem;} #zip-messaging-container #partPayCalculatorWidget #partPayCalculatorWidgetText {display: inline;font-size: 14px;} #zip-messaging-container #partPayCalculatorWidget #partPayCalculatorWidgetText br {display: none;} #zip-messaging-container #partPayCalculatorWidget #partPayCalculatorWidgetText #partPayCalculatorWidgetTextFromCopy {margin-right: 0;}`;
                    const style = document.createElement('style');
                    document.head.appendChild(style);
                    style.type = 'text/css';
                    style.id = 'zip-styles-head';
                    style.appendChild(document.createTextNode(css));
                }

                const zipScript = document.createElement('script');
                const holder = document.getElementById('zip-messaging-container');
                //we need to check if the JS is already appended or not - to prevent double widget being loaded
                if (!holder || (holder && holder.firstChild && holder.firstChild.src)) return;
                holder.innerHTML = '';
                zipScript.async = true;
                zipScript.src = `https://widgets.partpay.co.nz/zip-widget-classic-v3.0.0.js?type=calculator&min=0&max=1000&amount=${amount}&locale=uk`;
                holder.appendChild(zipScript);
            }
        }

        function getBasketDiscountAmount() {
            return gm.basketResponse.currencySymbol + (gm.basketResponse.grandTotal.raw.withTax * 0.2).toFixed(2);
        }

        function checkBasketContainShipFromStoreItems() {
            return gm.basketResponse.deliveryPlans.length > 0 ? true : false;
        }

        function validateMembership() {
            var membershipBasket = false;
            if (gm.userHasMembership == 1 && gm.basketResponse != null) {
                angular.forEach(gm.basketResponse.lineItems, function (item) {
                    if (item != null && item.isMembership == true && item.itemType == 2) {
                        membershipBasket = true;
                    }
                });

                if (membershipBasket == true) {
                    $(".membershipBasketErrorMsg").fadeIn();
                    gm.showMembershipBasketErrorMsg = true;
                    $timeout(function () {
                        $(".membershipBasketErrorMsg").fadeOut();
                        gm.showMembershipBasketErrorMsg = false;
                    }, 10000);
                    membershipBasket = false;
                    return;
                }
            }
        }

        function showBasketWarning() {
            return ((gm.basketContainShipFromStoreItems && gm.basketTouched) || (gm.outofStockProducts != null && gm.outofStockProducts.length > 0)) && gm.isMultiFulfilmentEnabled ? true : false;
        }

        function allItemsOOS() {
            return (gm.outofStockProducts != null && gm.outofStockProducts.length == (gm.basketResponse.lineItems.length + gm.outofStockProducts.length)) ? true : false;
        }

        function someItemsOOS() {
            return (gm.outofStockProducts != null && gm.outofStockProducts.length > 0 && gm.outofStockProducts.length != (gm.basketResponse.lineItems.length + gm.outofStockProducts.length)) ? true : false;
        }

        gm.getDeliveryPlansSorted = getDeliveryPlansSorted;
        function getDeliveryPlansSorted(deliveryPlans) {
            return deliveryPlans.sort(sortDeliveryPlansByType);
        }

        gm.WAREHOUSE = 'warehouse';
        function sortDeliveryPlansByType(a, b) {
            if ((a.deliveryCenter.code.toLowerCase().indexOf(gm.WAREHOUSE) > -1) && (b.deliveryCenter.code.toLowerCase().indexOf(gm.WAREHOUSE) > -1)) {
                return 0;
            } else if (a.deliveryCenter.code.toLowerCase().indexOf(gm.WAREHOUSE) > -1) {
                return -1;
            } else {
                return 1;
            }
        }

        // MEMBERSHIP SIGNUP
        gm.membershipSignupOptions = [];
        gm.membershipSignupSelectedOption = null;
        gm.memSignApplyDiscounCode = false;
        gm.fetchingSignupOptions = false;
        gm.currentMembership = typeof currentMembership != "undefined" ? currentMembership : null;

        if (gm.isBasketPage) {
            getMembershipSignupOptions();
        }

        function getMembershipSignupOptions() {
            if (gm.fetchingSignupOptions) return;
            gm.fetchingSignupOptions = true;
            $http.get(MEMBERSHIP.URL_SIGNUP_OPTIONS)
                .success(function (res) {
                    if (res && res.length === 0) return;
                    //we can signup. Assign options to global array
                    gm.membershipSignupOptions = res;

                    //override the top tier voucher count
                    angular.forEach(gm.membershipSignupOptions, function (benefit) {
                        if (benefit['stockCode'] === "53222") {
                            benefit['noOfVouchers'] = "UNLIMITED";
                        }
                    });

                    //assign modal listeners
                    $('#tfs-membership-signup-modal').on('show.bs.modal', function () {
                        document.documentElement.style.overflowY = "hidden";
                        resetMembershipSignupModal();
                    })

                    $('#tfs-membership-signup-modal').on('hide.bs.modal', function () {
                        document.documentElement.style.overflowY = "unset";
                        resetMembershipSignupModal();
                    })
                })
                .error(function (error) {
                    console.log('Error fetching membership signup options.');
                })
                .finally(function () {
                    gm.fetchingSignupOptions = false;
                    console.log('Membership signup options fetched.');
                });
        }

        function resetMembershipSignupModal() {
            // This happens outside of angularJS, we wrap it in a timeout
            $timeout(function () {
                gm.membershipSignupSelectedOption = null;
            })
        }

        gm.addMembershipToBag = addMembershipToBag;
        function addMembershipToBag(stockCode) {
            if (gm.apiPendingTfs) return;
            gm.apiPendingTfs = true;
            $http.get(`${MEMBERSHIP.URL_SIGNUP_ADD}?sku=${stockCode}`)
                .success(function (res) {
                    if (!res.isValid) {
                        gm.apiPendingTfs = false;
                        tfsNewAlert("Something went wrong. Try again.", "error");
                        return;
                    };
                    //check if we need to apply the first discount or not
                    if (gm.memSignApplyDiscounCode) {
                        sessionStorage.setItem(gm.applyMembershipVoucherAfterRedirect, true);
                    }
                    window.location.reload();
                })
                .error(function (error) {
                    gm.apiPendingTfs = false;
                    tfsNewAlert("Something went wrong. Try again.", "error")
                })
                .finally(function () {
                    console.log('Membership added to basket.');
                });
        }

        function changeBaseCurrencyV2(changeToCurrencyCode) {
            if (changeToCurrencyCode == null) {
                changeToCurrencyCode = $.cookie(CURRENCYCOOKIE.CurrencyCode);
            }
            if (changeToCurrencyCode) {
                $http.get('/Home/UpdateCurrencySetting' + "?currency=" + changeToCurrencyCode).then(function (resp) {
                    $.cookie("_ctcc", changeToCurrencyCode, { path: '/', expires: 1000 });
                    $.cookie("basecurrencyv2", 1, { path: '/', expires: 1000 });
                    window.location.reload();
                }, function (error) {
                });
            }
        };
    };
})();
;
(function () {
    'use strict';
    window.app.controller('productCtrl', productCtrl);
    window.app.constant("CURRENCYCOOKIE", {
        'CurrencyCode': "_ctcc"
    });
    productCtrl.$inject = ['$scope', '$timeout', 'productConfig', 'model', '$http', '$q', '$sce', 'CURRENCYCOOKIE', 'loader'];

    function productCtrl($scope, $timeout, productConfig, model, $http, $q, $sce, CURRENCYCOOKIE) {
        var pm = this;
        pm.model = model;
        pm.addToBag = false;
        pm.productResponse = {};
        pm.searchCriteria = {};
        pm.itemsPerPage = 12;
        pm.currentPage = 0;
        pm.productCount = 1;
        pm.priceWithEngraving = 0;
        pm.productTosearch = productTosearch;
        pm.searchproductfilter = [];
        pm.initProducts = initProducts;
        pm.initCollectionProducts = initCollectionProducts;
        pm.searchProducts = searchProducts;
        pm.searchAddProduct = searchAddProduct;
        pm.clearAddProduct = clearAddProduct;
        //pm.variantDetail = variantDetail;
        pm.productDetail = productDetail;
        pm.productQty = productQty;
        pm.initBrandListing = initBrandListing;
        pm.filterBrandListing = filterBrandListing;
        pm.fetchSubBrandProductList = fetchSubBrandProductList;
        pm.filterBrands = filterBrands;
        pm.getUrl = getUrl;
        pm.paging = paging;
        pm.temp = 0;
        pm.addToWishlist = addToWishlist;
        pm.wishlistexistserror = false;
        pm.WishlistFilter = { id: '' };
        pm.wishlistsaved = false;
        pm.wishlisterror = false;
        pm.removeFilter = removeFilter;
        pm.selectionGroup = [];
        pm.selectedKey = ""
        pm.item = [];
        $scope.noRecord = false;
        pm.subBrandProducts = [];
        pm.selectedRecord = '';
        pm.setRating = setRating;
        pm.removeChar = removeChar;
        pm.userLogin = userLogin;
        pm.registration = registration;
        pm.reviewAsGuest = reviewAsGuest;
        pm.cancel = cancel;
        pm.addReview = addReview;
        pm.configRating = configRating;
        pm.addMultipleToWishlist = addMultipleToWishlist;
        pm.addMultipleToBasket = addMultipleToBasket;
        pm.showAllbrand = false;
        pm.hideQickView = hideQickView;
        pm.subBrandPagination = subBrandPagination;
        pm.initProductVariant = initProductVariant;
        pm.getToWishlist = getToWishlist;
        pm.checkForWishlist = checkForWishlist;
        pm.getBasketRelatedProducts = getBasketRelatedProducts;
        pm.getAvailableAttributeValues = getAvailableAttributeValues;
        pm.relatedProducts = [];
        pm.GetDynamicReviewConfig = GetDynamicReviewConfig;
        pm.beginQuestionnaire = beginQuestionnaire;
        pm.submitSurvey = submitSurvey;
        pm.rotateImage = rotateImage;
        pm.degree = 0;
        pm.onTextFocus = onTextFocus;
        pm.checkForSpecificAttributeinProductList = checkForSpecificAttributeinProductList;
        pm.IsUserLoggedIn = ($.cookie('IsUserLoggedIn') === undefined) ? false : ($.cookie('IsUserLoggedIn') == 'true');
        pm.COOKIE_LIMIT = 15;
        pm.PRODUCT_COOKIE = '_rvp';
        pm.PRODUCT_COOKIE_LIST = '_rvpList';
        pm.getGrid = getGrid;
        pm.getList = getList;
        pm.getView = true;
        pm.getHtml = getHtml;
        pm.videoPopupModal = videoPopupModal;
        pm.getStoreStockAvailability = getStoreStockAvailability;
        pm.deletedFromWishlist = deletedFromWishlist;
        pm.getProductReview = getProductReview;
        pm.productAvgRating = 0;
        pm.showAddToBag = true;
        pm.showAddToQueue = false;
        pm.showAddToSubscriptionList = false;
        pm.slugifyUrl = slugifyUrl;
        pm.EngravingItemType = '10';
        pm.evalButtonVisibility = evalButtonVisibility;
        pm.checkStockAvailabilityStatus = checkStockAvailabilityStatus;
        pm.IsDeletedFromWishlist = false;
        pm.searchCollectionProducts = searchCollectionProducts;
        pm.collectionProuducts = null;
        pm.collectionList = [];
        pm.searchPaginated = searchPaginated;
        pm.emptyGuid = '00000000-0000-0000-0000-000000000000';
        pm.fetchMoreReviews = fetchMoreReviews;
        pm.hideGiftCardMsg = hideGiftCardMsg;
        pm.changeBaseCurrency = changeBaseCurrency;
        pm.changeCurrecyValueForEngraving = changeCurrecyValueForEngraving;
        pm.brandCarousels = brandCarousels;
        pm.enableChangeBaseCurrencyV2 = 0;

        if (pm.model.recordId) {
            var recentProducts = $.cookie(pm.PRODUCT_COOKIE);
            if (recentProducts) {
                var itemsInCookies = recentProducts.split(",");
                if (itemsInCookies) {
                    var flag = 1;
                    angular.forEach(itemsInCookies, function (value, key) {
                        if (value == pm.model.recordId) {
                            flag = 0;
                        }
                    });
                    if (flag) {
                        if (itemsInCookies.length > pm.COOKIE_LIMIT) {
                            angular.forEach(itemsInCookies, function (value, key) {
                                itemsInCookies[key] = itemsInCookies[key + 1];
                            });
                            itemsInCookies[itemsInCookies.length - 1] = pm.model.recordId;
                            recentProducts = itemsInCookies.join(',');
                        }
                        else {
                            itemsInCookies.push(pm.model.recordId);
                            recentProducts = itemsInCookies.join(',');
                        }
                        $.removeCookie(pm.PRODUCT_COOKIE);
                        $.cookie(pm.PRODUCT_COOKIE, recentProducts, { path: '/' });
                    }
                }
            }
            else {
                $.cookie(pm.PRODUCT_COOKIE, pm.model.recordId, { path: '/' });
            }
        }

        //For Product Recommendation
        if (pm.model.stockCode) {
            var recentProductsList = $.cookie(pm.PRODUCT_COOKIE_LIST);
            if (recentProductsList) {
                var itemsInCookies = recentProductsList.split(",");
                if (itemsInCookies) {
                    var flag = 1;
                    angular.forEach(itemsInCookies, function (value, key) {
                        if (value == pm.model.stockCode) {
                            flag = 0;
                        }
                    });
                    if (flag) {
                        if (itemsInCookies.length > pm.COOKIE_LIMIT) {
                            angular.forEach(itemsInCookies, function (value, key) {
                                itemsInCookies[key] = itemsInCookies[key + 1];
                            });
                            itemsInCookies[itemsInCookies.length - 1] = pm.model.stockCode;
                            recentProductsList = itemsInCookies.join(',');
                        }
                        else {
                            itemsInCookies.push(pm.model.stockCode);
                            recentProductsList = itemsInCookies.join(',');
                        }
                        $.removeCookie(pm.PRODUCT_COOKIE_LIST);
                        $.cookie(pm.PRODUCT_COOKIE_LIST, recentProductsList, { path: '/' });
                    }
                }
            }
            else {
                $.cookie(pm.PRODUCT_COOKIE_LIST, pm.model.stockCode, { path: '/' });
            }
        }


        function getBasketRelatedProducts(basketId) {
            $http.post(productConfig.basketRelatedProducts + '/' + basketId).success(function (resp) {
                if (resp != null) {
                    pm.relatedProducts = resp;
                }
            })
        };
        function checkForSpecificAttributeinProductList(attributeCode, attributevalue, grp, list) {
            var flag = false;
            if (list != null) {
                angular.forEach(list, function (line) {
                    if (line.groupName.includes(grp)) {
                        var attr = line.attributes
                        if (attr != null) {
                            for (i = 0; i < attr.length; i++) {
                                // this can be a string or null
                                var FieldCode = attr[i].key;
                                var FieldValue = attr[i].value;
                                if (FieldCode != null && FieldCode != "" && FieldCode == attributeCode) {
                                    //line.customInfo1 = FieldCode + "" + FieldValue;
                                    if (FieldValue != null && FieldValue == attributevalue) {
                                        flag = true;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if (flag)
                        return flag;
                });
                return flag;
            }
        }


        function initProducts(responseModel) {
            if (responseModel == null) {
                responseModel = pm.model;
            }
            pm.productResponse = responseModel;
            //bind gradient value with product 
            //angular.forEach(pm.productResponse.results, function (item) {
            //    angular.forEach(item.attributes, function (attr) {
            //        if (attr.key == "gradient") {
            //            item.title = attr.value;
            //        }
            //    });
            //});
            pm.searchCriteria = responseModel.searchCriteria;
            //if (pm.productResponse.customFieldValue != null && pm.productResponse.customFieldValue != "")
            //    pm.sortItems = JSON.parse(pm.productResponse.customFieldValue);
            pm.itemsPerPage = pm.searchCriteria.pageSize;
            pm.currentPage = pm.searchCriteria.currentPage;
            pm.sortByList = responseModel.sortList;
            pm.searchCriteria.sortBy = responseModel.sortBy;
            pm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
            pm.changeBaseCurrency(pm.currencyCookie);
        };

        function initCollectionProducts(responseModel) {
            pm.productResponse = responseModel.collectionResult;
            if (pm.productResponse == null || pm.productResponse.results == null)
                $scope.noRecord = true;
            if (pm.productResponse != null) {
                pm.searchCriteria = responseModel.collectionResult.searchCriteria;
                pm.itemsPerPage = pm.searchCriteria.pageSize;
                pm.currentPage = pm.searchCriteria.currentPage;
                pm.sortByList = responseModel.collectionResult.sortByList;

            }
        };
        function removeFilter(filter) {
            if (filter.freeText == undefined) {
                productTosearch({ key: filter.key, name: filter.name }, { name: filter.value, isSelected: false });
            } else {
                pm.searchCriteria.freeText = '';
                pm.searchAddProduct();
            }
        }
        function productTosearch(filter, item) {
            pm.selectedKey = '';
            if (item.isSelected) {
                pm.selectedKey = filter.key;
                pm.searchproductfilter.push({ "key": filter.key, "value": item.name, "isSelected": true, name: filter.name });
            }
            else {
                for (var i = 0; i < pm.searchproductfilter.length; i++) {
                    if (pm.searchproductfilter[i].key == filter.key && pm.searchproductfilter[i].value == item.name) {
                        pm.searchproductfilter.splice(i, 1);
                    }
                }
            }
            pm.selectionGroup = [];
            for (var i = 0; i < pm.searchproductfilter.length; i++) {
                if (pm.selectionGroup.indexOf(pm.searchproductfilter[i].name) == -1) {
                    pm.selectionGroup.push(pm.searchproductfilter[i].name);
                }
            }
            pm.searchAddProduct();
        };


        function searchAddProduct() {
            pm.searchfilter = { "currentPage": 1, "collectionId": pm.searchCriteria.collectionId, "pageSize": pm.searchCriteria.pageSize, "filters": pm.searchproductfilter, "freeText": pm.searchCriteria.freeText, "sortBy": pm.searchCriteria.sortBy, "allowFacet": "true", "categoryIds": pm.searchCriteria.categoryIds, "brandId": pm.searchCriteria.brandId, "facet": pm.searchCriteria.facet, "categoryId": pm.searchCriteria.categoryId, "excludedBrandIds": pm.searchCriteria.excludedBrandIds, "excludedCategoryIds": pm.searchCriteria.excludedCategoryIds };
            pm.searchProducts(pm.searchfilter);
        };


        function clearAddProduct(fieldId) {
            pm.selectedKey = '';
            pm.selectionGroup = [];
            $scope.fieldId = false;
            for (var i = 0; i < pm.searchproductfilter.length; i++) {
                if (pm.searchproductfilter[i].key == fieldId) {
                    pm.searchproductfilter.splice(i, 1);
                    i = i - 1;
                } else {
                    if (pm.selectionGroup.indexOf(pm.searchproductfilter[i].name) == -1) {
                        pm.selectionGroup.push(pm.searchproductfilter[i].name);
                    }
                }
            }

            pm.searchAddProduct();
        };

        function paging(pagination) {
            pm.searchCriteria = { "filters": pm.searchproductfilter, "currentPage": pagination.currentPage, "pageSize": pagination.pageSize, "categoryIds": pm.searchCriteria.categoryIds, "categoryId": pm.searchCriteria.categoryId };
            Products(pm.searchCriteria);
        };

        function productDetail(id) {
            $scope.productmodal = false;
            $http.post(productConfig.productUrl, { id: id })
                .success(function (data) {
                    pm.model = data;
                    pm.variants = data != null ? data.variant : null;
                    if (pm.variants != null) {
                        pm.initProductVariant(pm.variants);
                    }
                    if (data != null)
                        pm.productId = data.recordId;
                    $scope.productmodal = true;
                    pm.model.bulkQty = 1;
                    pm.checkForWishlist();
                    $timeout(function () { $("#qtyBox").focus().select(); $("#qtyBoxBundle").focus().select(); }, 2000);
                })
                .error(function (msg) {
                    pm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    pm.saving = false;
                });
        };

        function searchPaginated(filter) {
            if ((filter.collectionId == pm.emptyGuid || filter.collectionId == null || filter.collectionId == "") &&
                (filter.brandId == pm.emptyGuid || filter.brandId == null || filter.brandId == ""))
                window.location = '/search?page=' + filter.currentPage
            else {
                searchProducts(filter);
            }

        }

        function searchProducts(searchFilter) {
            $http.post(productConfig.searchProductUrl, searchFilter)
                .success(function (data) {
                    $('html,body').animate({ scrollTop: 0 }, 'slow');
                    pm.productResponse.results = data.results;
                    //bind gradient value with product 
                    angular.forEach(pm.productResponse.results, function (item) {
                        angular.forEach(item.attributes, function (attr) {
                            if (attr.key == "gradient") {
                                item.title = attr.value;
                            }
                        });
                    });

                    if (typeof (data.groups) !== undefined && data.groups !== null) {
                        pm.productResponse.productGroupModel.groups = data.groups;
                    }
                    angular.forEach(pm.productResponse.results, function (pro) {
                        pro.bulkQty = 1;
                    });
                    pm.productResponse.total = data.total;
                    pm.searchCriteria = data.searchCriteria;
                    pm.itemsPerPage = pm.searchCriteria.pageSize;
                    pm.currentPage = pm.searchCriteria.currentPage;
                    if (data.results.length == 0)
                        $scope.noRecord = true;
                    else
                        $scope.noRecord = false;
                    var filter = {};
                    angular.forEach(pm.productResponse.filters, function (value, i) {
                        if (pm.selectedKey == value.key) {
                            filter = value;
                        }
                    });
                    pm.productResponse.filters = data.filters;
                    //pm.productResponse.groupsWithProducts = [];
                    //if (pm.productResponse.productGroupModel && pm.productResponse.productGroupModel.groups && pm.productResponse.productGroupModel.groups.length <= 0) {
                    //    pm.productResponse.groupsWithProducts.push({ groupName: "", products: pm.productResponse.results });
                    //}
                    //else {
                    //    var groups = [];
                    //    if (pm.sortItems != undefined) {
                    //        angular.forEach(pm.sortItems, function (sortGrp) {
                    //            angular.forEach(pm.productResponse.filterCriteria, function (grp) {
                    //                if (sortGrp.key == grp.attributeValue) {
                    //                    groups.push(sortGrp.value);
                    //                }
                    //            });
                    //        });
                    //    }
                    //}
                    //if (groups.length > 0)
                    //    pm.productResponse.productGroupModel.groups = groups;

                    //if (pm.productResponse.productGroupModel) {
                    //    for (var i = 0; i < pm.productResponse.productGroupModel.groups.length; i++) {
                    //        var products = [];
                    //        for (var j = 0; j < pm.productResponse.results.length; j++) {
                    //            if (pm.productResponse.productGroupModel.groups[i] == pm.productResponse.results[j].groupName) {
                    //                products.push(pm.productResponse.results[j]);
                    //            }
                    //            var grpName = [];
                    //            grpName = pm.productResponse.results[j].groupName.split(',');
                    //            if (grpName && grpName.length > 1) {
                    //                if (grpName.find(ele => ele == pm.productResponse.productGroupModel.groups[i])) {
                    //                    products.push(pm.productResponse.results[j]);
                    //                }
                    //            }
                    //        }
                    //        if (products.length > 0)
                    //            pm.productResponse.groupsWithProducts.push({ groupName: pm.productResponse.productGroupModel.groups[i], products: products });
                    //    }
                    //}
                    //else {
                    //    if (pm.productResponse.results != null) {
                    //        pm.productResponse.groupsWithProducts.push({ groupName: "", 'products': pm.productResponse.results });
                    //    }

                    //}
                    //window.setTimeout(function () { imgix.init({ force: true });}, 1000);

                    //PubSub.publish("search", prodDetail);


                })
                .error(function (msg) {

                })
                .finally(function () {
                });
        };

        if (sessionStorage.getItem('addToWishlist') !== null) {
            addToWishlist(pm.model.recordId);
        }

        function addToWishlist(id) {
            pm.WishlistFilter.id = id;
            $(".add-wishlist-btn").attr("disabled", "true");
            $http.post(productConfig.addToWishlistUrl, pm.WishlistFilter).success(function (resp) {
                //$(".wishdiv").fadeIn();
                if (resp) {
                    pm.wishlistsaved = true;
                }
                else {
                    pm.wishlistexistserror = true;
                    pm.wishlisterror = false;
                }
                $timeout(function () {
                    $(".wishdiv").fadeOut();
                    pm.checkForWishlist();
                    pm.wishlistsaved = false;
                    pm.wishlistexistserror = false;
                }, 2000);
            }).error(function (msg) {
                //$(".wishdiv").fadeIn();
                pm.wishlisterror = true;
                //$timeout(function () {
                //    $(".wishdiv").fadeOut();
                //}, 2000);
            }).finally(function (data) {
                sessionStorage.removeItem('addToWishlist');
                $(".add-wishlist-btn").removeAttr("disabled");
            });;
        };

        function initBrandListing() {
            $('#brandContainer').html($('#ALL').html());
            $('#brandContainer').quicksand($('#ALL').find('div[parent=1]'), { duration: 1, attribute: 'data-id', adjustHeight: 'dynamic' });
        };

        function filterBrandListing(letter) {
            if (letter == 'ALL') {
                pm.showAllbrand = true;
                $('#brandContainer').quicksand($('#ALL').find('div[parent=1]'), { duration: 1, attribute: 'data-id', adjustHeight: 'dynamic' });
            }

            else {
                pm.showAllbrand = false;
                var test = $('div:contains("' + letter + '")');
                $('#brandContainer').quicksand($('#ALL').find('div[firstchar="' + letter + '"]'), { duration: 1, attribute: 'data-id', adjustHeight: 'dynamic' });
                pm.result = $('#ALL').find(test);
            }
        };

        function filterBrands(letter) {
            if (letter == null || letter.length == 0) {
                pm.showAllbrand = true;
                $('#brandContainer').html($('#ALL').html());
                $('#brandContainer').quicksand($('#ALL').find('div[parent=1]'), { duration: 1, attribute: 'data-id', adjustHeight: 'dynamic' });
            }
            if (letter == null || letter.length < 2) return;
            pm.selectedRecord = letter;
            pm.showAllbrand = false;
            if (letter == '#') { letter = ''; }
            letter = letter.toUpperCase();
            letter = letter.charAt(0).toLowerCase() + letter.slice(1);
            if (!isNaN(letter.charAt(0)) || letter.indexOf('+') !== -1) {
                letter = '#' + letter;
            }
            var test = $('div:contains("' + letter + '")');
            $('#brandContainer').quicksand($('#ALL').find(test), { duration: 1, attribute: 'data-id', adjustHeight: 'dynamic' });
            pm.result = $('#ALL').find(test);

        };
        function getUrl() {
            pm.url = window.location.origin;
        };

        function fetchSubBrandProductList(subBrand, parentBrand) {
            $http.post(productConfig.fetchSubBrandProducts, { id: parentBrand, subBrandId: subBrand }).success(function (resp) {
                pm.subBrandProducts = resp[0].products;
                pm.subBrandProducts.currentPage = 1;
                pm.subBrandProducts.pageSize = 12;
                pm.subBrandProducts.total = pm.subBrandProducts.length;
                pm.subBrandPaginated = pm.subBrandProducts.slice(0, pm.subBrandProducts.pageSize);
                //$timeout(function () { $(".wishdiv").fadeOut(); }, 2000);
            })
                .error(function (msg) {
                    //pm.wishlisterror = true;
                    //$timeout(function () {
                    //    $(".wishdiv").fadeOut();
                    //}, 2000);
                })
                .finally(function () {
                });

        };

        function subBrandPagination(subBrandProducts) {

            pm.subBrandPaginated = pm.subBrandProducts.slice((subBrandProducts.pageSize * subBrandProducts.currentPage) - subBrandProducts.pageSize, subBrandProducts.pageSize * subBrandProducts.currentPage);
        }

        function setRating(value, isActive) {
            pm.rate = [];
            if (isActive == 1) {
                for (var i = 1; i <= value; i++) {
                    pm.rate.push(i);
                }
            }
            else {
                for (var i = value; i < 5; i++) {
                    pm.rate.push(i);
                }
            }
            return pm.rate;

        };
        function removeChar(fielId, name) {
            var value = fielId.replace(/[^a-zA-Z0-9]/g, '') + name.replace(/[^a-zA-Z0-9]/g, '');
            return value;
        };

        function registration(model) {
            pm.errorMessage = null;
            pm.registerErrors = true;
            pm.loginErrors = false;
            $http.post(productConfig.register, model)
                .success(function (data) {
                    if (data) {
                        $("#productReviewLogin").modal('hide');
                        pm.writeReview = true;
                        pm.reviewAsGuest();
                    }
                })
                .error(function (msg) {
                    pm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    $timeout(function () { $(".alertBlock").fadeOut(); }, 3000);
                });
        };

        function userLogin(model) {
            pm.errorMessage = null;
            pm.loginErrors = true;
            pm.registerErrors = false;
            $(".alertBlock").fadeIn();
            $http.post(productConfig.signIn, model)
                .success(function (data) {
                    if (data) {
                        $("#productReviewLogin").modal('hide');
                        pm.writeReview = true;
                        pm.reviewAsGuest();
                    }
                })
                .error(function (msg) {
                    pm.errorMessage = msg.errorMessages;
                    $timeout(function () {
                        $(".alertBlock").fadeOut();
                    }, 3000);

                })
                .finally(function () {
                });
        };

        function reviewAsGuest() {
            $('html,body').animate({ scrollTop: 980 }, 'slow');
            $("#collapse1").removeClass("in");
            $("#collapse3").addClass("in");
        };

        function cancel() {
            $('html,body').animate({ scrollTop: 300 }, 'slow');
            $("#collapse3").removeClass("in");
            $("#collapse1").addClass("in");
        };

        function addReview(id, model, form) {
            if (form.$invalid) {
                return;
            }
            model.reviewSections = pm.reviewSections;
            model.section = pm.reviewSections[0];
            $http.post(productConfig.addReview, { id: id, productReview: model })
                .success(function (data) {
                    $("#SuccessAlert").modal();
                    form.$setPristine();
                    form.$setUntouched();
                    pm.model.review = {};
                    pm.writeReview = false;
                    $timeout(function () {
                        $("#SuccessAlert").modal('hide');
                        $("#collapse3").removeClass("in");
                        $("#collapse1").addClass("in");
                    }, 2000);
                    $timeout(function () {
                        window.location.reload();
                    }, 3000);
                })
                .error(function (msg) {
                    //pm.errorMessage = msg.errorMessages;
                    //$timeout(function () {
                    //    $(".alertBlock").fadeOut();
                    //}, 3000);

                })
                .finally(function () {
                });
        };
        function configRating(value) {
            pm.trueRating = pm.setRating(value, 1);
            pm.falseRating = pm.setRating(5 - value, 1);
        };

        function GetDynamicReviewConfig() {
            $http.post(productConfig.reviewConfig).then(function (success) {
                pm.reviewSections = success.data;
            }, function (error) { });
        }

        function addMultipleToWishlist(products, isMultiple) {
            pm.modelList = [];
            if (isMultiple == 1) {
                pm.modelList.push({ "productId": products.productId, "qty": 0, "displayOrder": 0 });
                $scope.$parent.gm.addToBasket(products.productId, 0);
            }
            else {
                for (var i = 0; i < products.length; i++) {
                    pm.modelList.push({ "productId": products[i].productId, "qty": 0, "displayOrder": 0 });
                    $scope.$parent.gm.addToBasket(products[i].productId, 0);
                }
            }
            $http.post(productConfig.basketToWishlist, pm.modelList).success(function (resp) {
                if (resp) {
                    pm.wishlistsaved = true;
                }
                else {
                    pm.wishlistexistserror = true;
                }
                $("html, body").animate({ scrollTop: 0 }, "slow");
                $timeout(function () { window.location.reload(); }, 3000);
            })
                .error(function (msg) {
                })
                .finally(function () {
                    pm.getToWishlist(pm.productResponse.results);
                });
        };
        function checkForWishlist() {
            pm.IsUserLoggedIn = $.cookie('IsUserLoggedIn');
            $http.post(productConfig.getWishlist).success(function (resp) {
                if (resp != null && pm.productId != null) {
                    angular.forEach(resp, function (resp, key) {
                        if (pm.productId == resp.recordId) {
                            pm.model.inWishList = true;
                        }
                    });
                }
            })
                .finally(function () {
                });
        };

        function getToWishlist(products) {
            $http.post(productConfig.getWishlist).success(function (resp) {
                if (resp != null && products != null) {
                    angular.forEach(products, function (product, key) {
                        angular.forEach(resp, function (resp, key) {
                            if (product.id == resp.id) {
                                product.inWishList = true;
                            }
                        });
                    });
                }
            })
                .finally(function () {
                });
        };
        function addMultipleToBasket(products, memberShipAlert) {
            if (memberShipAlert != null && memberShipAlert.length > 0) {
                $("#wishListModal").modal('hide');
                pm.membershipAlreadyAdded = true;
                $timeout(function () {
                    $(".membershipAlreadyAdded").fadeOut();
                    pm.membershipAlreadyAdded = false;
                }, 2000);
                return;
            }
            pm.modelList = [];
            for (var i = 0; i < products.length; i++) {
                pm.modelList.push({ "productId": products[i].recordId, "qty": 1, "displayOrder": 0, isSubscription: products[i].subscriptionEnabled });
            }
            $http.post(productConfig.wishlistToBasket, pm.modelList).success(function (resp) {
                window.location.reload();
            })
                .error(function (msg) {
                })
                .finally(function () {
                });
        };

        function hideQickView() {
            $("#product-quick-view-modal").modal("hide");
        }

        //gets the possible attribute values for the selected attribute & its value. Uses the pm.model.variantProducts
        //sample call getAvailableAttributeValues('size', '6', products);      //=> {size: ['6'], color: ['black', 'blue']}
        function getAvailableAttributeValues(attrCode, attrValue, isSelected, independentUrl) {
            pm.addToBag = false;
            if (isSelected) { return; }
            var selectedValues = [];
            //angular.forEach();
            //1. Set attributes available = false & selected = false for all 
            pm.model.variantProductsAttribute.forEach(function (attr) {
                attr.fieldValues.forEach(function (val) {
                    val.available = false;
                    if (attr.fieldCode == attrCode) {
                        if (val.fieldValue == attrValue) {
                            val.selected = true;
                        } else {
                            val.selected = false;
                        }
                    }
                    if (val.selected == true)
                        selectedValues.push(val.fieldValue);
                })
            });

            //2. pick up all the proudcts that match the attrCode & attrValue passed. 
            var availableAttrs = [];
            var matchedProd = [];
            pm.model.variantProducts.forEach(function (prod) {
                var matchedAttrAndValue = prod.variantAttributes.filter(function (pAttr) {
                    return pAttr.fieldCode === attrCode & pAttr.fieldValue === attrValue;
                })

                if (matchedAttrAndValue.length > 0) {

                    //console.log(MoviesCtrl(selectedValues, prod.variantAttributes));
                    //if (selectedValues.every(function (val) { return prod.variantAttributes.indexOf(val) >= 0; }))
                    //    matchedProd.push(prod);
                    var matchedAttribute = [];
                    prod.variantAttributes.forEach(function (pAttr) {
                        selectedValues.filter(function (pAttr1) {
                            pAttr.selected = pAttr1;
                            if (pAttr1 === pAttr.fieldValue) { matchedAttribute.push(pAttr1) } return matchedAttribute;
                        })
                        //TODO: check that the same attribute & value does not exist already in the array before pushing it in
                        availableAttrs.push(pAttr);
                    })
                    if (matchedAttribute.length == prod.variantAttributes.length) { matchedProd.push(prod); }
                }
            });

            //3. pick up all the attributes + values (other than the clicked one) from products and set their isAvailable = true in MasterAttributes array
            pm.model.variantProductsAttribute.forEach(function (attr) {
                //the attribute passed in selection, shoudl have all the values as "avaialble" and clicked item to be "selected"
                if (attr.fieldCode === attrCode) {
                    attr.fieldValues.forEach(function (val) {
                        val.available = true;
                        if (val.fieldValue == attrValue) val.selected = true;
                        if (val.selected == true) {
                            if (val.available == true) {
                                attr.selectedValue = val.fieldValue;

                            }
                            else {
                                attr.selectedValue = "";
                                pm.addToBag = true;
                            }
                        }
                    });
                }
                else {
                    attr.fieldValues.forEach(function (val) {
                        if (availableAttrs.filter(function (availAttr) {
                            return availAttr.fieldCode === attr.fieldCode & availAttr.fieldValue === val.fieldValue;
                        }).length > 0) {
                            val.available = true;
                        }
                        if (val.selected == true) {
                            if (val.available == true) {
                                attr.selectedValue = val.fieldValue;

                            }
                            else {
                                attr.selectedValue = "";
                                pm.addToBag = true;
                            }
                        }
                    })
                }
            });

            if (matchedProd.length > 0) {
                $scope.productId = matchedProd[0].productId;
                $http.post(productConfig.productUrl + "/" + $scope.productId).success(function (resp) {
                    if (resp !== null) {
                        //if (pm.model.classification.mainCategoryName != null && pm.model.classification.mainCategoryName.toLowerCase() == 'scent addict') {
                        //    pm.showAddToBag = attrValue == 'one-time-purchase' ? true : false;
                        //}
                        if (independentUrl) {
                            window.location.href = "/" + resp.link;
                        }
                        else {
                            pm.productId = $scope.productId;
                            var attributes = pm.model.variantProductsAttribute;
                            var variantProducts = pm.model.variantProducts;
                            pm.model = resp;
                            pm.model.reviews = pm.reviews;
                            pm.model.variantProductsAttribute = attributes;
                            pm.model.variantProducts = variantProducts;
                            pm.image = pm.model !== null ? pm.model.image : null;
                            pm.model.engravingProduct = [];
                            angular.forEach(pm.model.relatedProductList, function (prod) {
                                if (prod.itemType == pm.EngravingItemType) {
                                    pm.model.engravingProduct.push(prod);
                                }
                            });
                            pm.priceWithEngraving = pm.model.price.raw.withTax + pm.model.engravingProduct[0].price.raw.withTax;
                            pm.evalButtonVisibility();
                            changeCurrecyValueForEngraving(pm.priceWithEngraving);
                        }
                    }
                });
            }
        }
        function evalButtonVisibility() {
            pm.showAddToBag = false;
            pm.showAddToQueue = false;
            pm.showAddToSubscriptionList = false;

            if (!pm.model.subscriptionEnabled) {
                pm.showAddToBag = true;
            }
            else {
                var isOtp = -1;
                //var isOtp = pm.model.variantProducts.findIndex(i => i.stockCode == pm.model.stockCode && i.variantAttributes[0].fieldValue == 'one-time-purchase');
                angular.forEach(pm.model.variantProducts, function (value, key) {
                    if (vProd.stockCode == pm.model.stockCode && vProd.variantAttributes[0].fieldValue == 'one-time-purchase') {
                        isOtp = key;
                    }
                });
                if (pm.model.variantProducts.length > 0 && isOtp == -1) {
                    pm.showAddToQueue = true;
                }
                else if (isOtp == -1) {
                    pm.showAddToSubscriptionList = true;
                }
                else {
                    pm.showAddToBag = true;
                }
            }
            pm.checkStockAvailabilityStatus();
        }
        function checkStockAvailabilityStatus() {
            if (pm.model.stockAvailability == 'Instock') {
                pm.stockAvailabilityMsg = 'In Stock';
            }
            else if (pm.model.stockAvailability == 'OutOfStock') {
                pm.stockAvailabilityMsg = 'Out of Stock';
            }
            else if (pm.model.stockAvailability == 'ClickNCollectOnly') {
                pm.stockAvailabilityMsg = 'Out of Stock - Available for Click & Collect';
            }
        }
        function initProductVariant() {
            pm.model.variantProductsAttribute.forEach(function (attr) {
                attr.fieldValues.forEach(function (val) { val.available = true; })
            });
            pm.model.engravingProduct = [];
            //pm.model.engravingProduct = pm.model.relatedProductList.filter(x => x.itemType == pm.EngravingItemType);
            angular.forEach(pm.model.relatedProductList, function (prod) {
                if (prod.itemType == pm.EngravingItemType) {
                    pm.model.engravingProduct.push(prod);
                }
            });
            pm.priceWithEngraving = pm.model.price.raw.withTax + pm.model.engravingProduct[0].price.raw.withTax;
            changeCurrecyValueForEngraving(pm.priceWithEngraving);
            var selectedProduct = pm.model.variantProducts.filter(function (p) { return p.stockCode === pm.model.stockCode; })[0];
            if (selectedProduct != undefined) {
                selectedProduct.variantAttributes.forEach(function (pAttr) {
                    var attrFromMaster = pm.model.variantProductsAttribute.filter(function (attr) { return attr.fieldCode === pAttr.fieldCode })[0];
                    var matchedAttr = attrFromMaster.fieldValues.filter(function (fieldVal) { return fieldVal.fieldValue === pAttr.fieldValue })[0];
                    matchedAttr.selected = true;
                    attrFromMaster.selectedValue = matchedAttr.fieldValue;
                });
            }
        }

        function productQty(qty) {
            if (pm.productCount == 1 && qty == -1) { return; }
            pm.productCount = parseInt(pm.productCount) + qty;
        }

        function beginQuestionnaire(productId, questionnaireCode) {
            pm.model.survey = {};
            $http.post(productConfig.questionnaireCode, { questionnaireCode: questionnaireCode }).success(function (resp) {
                pm.model.survey = resp;
                $('#QualifyingQuestionnaire').modal('show');
            });
        }

        function submitSurvey(productId) {

            //this is where we submit the whole survey using AJAX call.
            pm.surveyCompleted = true;
            var answers = []; var multipleAnswers = "";
            pm.model.survey.result.wrongOptionCount = 0;
            //save answers in an array
            angular.forEach(pm.model.survey.result.questions, function (value, key) {
                multipleAnswers = "";
                if (value.selectedOptionValue == "" || value.showHelpText == true) {
                    pm.model.survey.result.wrongOptionCount = (pm.model.survey.result.wrongOptionCount + 1);
                }
                if (multipleAnswers != "") {
                    answers.push({ "questionId": value.recordId, "question": value.question, "selectedAnswer": multipleAnswers });
                }
                else {
                    answers.push({ "questionId": value.recordId, "question": value.question, "selectedAnswer": value.selectedOptionValue });
                }
            });

            //save survey.
            if (pm.model.survey.result.wrongOptionCount == 0) {
                $http.post("/Survey/SaveAnswerBulk", { surveyId: pm.model.survey.result.recordId, answers: answers, productId: productId }).then(function (success) {
                    $('#QualifyingQuestionnaire').modal('hide');
                    pm.model.canAddToBag = true;
                }, function (error) { })
            }
        }

        function rotateImage(deg) {
            if (pm.degree == 270) {
                $(".magnify-image").removeClass("rotate" + pm.degree);
                pm.degree = 0;
            }
            else {
                $(".magnify-image").removeClass("rotate" + pm.degree);
                pm.degree += deg;
                $(".magnify-image").addClass("rotate" + pm.degree);
            }

        }
        function onTextFocus(event) {
            event.target.select();
        }
        function getGrid() {
            $("#view").addClass('gridView');
            $("#view").removeClass('listView');
            pm.getView = true;
        }
        function getList() {
            $("#view").removeClass('gridView');
            $("#view").addClass('listView');
            pm.getView = false;
        }

        PubSub.subscribe('wishListData', function (wishlistData) {
            pm.productModel = wishlistData;
        });

        function getStoreStockAvailability() {
            if (pm.postCode != null) {
                pm.noStore = false;
                pm.postCodeInValid = false;
                $http.post(productConfig.stockAvailabilityUrl, { stockCode: pm.model.stockCode, postCode: pm.postCode }).success(function (resp) {
                    pm.stores = resp;
                    if (pm.stores != null && pm.stores.length > 0) {
                        pm.showStoresOnMap(pm.stores);
                        $('#storeInfo').modal('show');
                        if (pm.stores != null) {
                            angular.forEach(pm.stores, function (store) {
                                store.distanceFromPostCode = Math.ceil(store.distanceFromPostCode);
                            });
                        }
                    }
                    else {
                        pm.noStore = true;
                    }
                });
            }
            else {
                pm.postCodeInValid = false;
                pm.postCodeInValid = true;
            }
        }
        pm.createMap = createMap;
        pm.showStoresOnMap = showStoresOnMap;
        function createMap() {
            var mapOptions = {
                zoom: 9,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            pm.map = new google.maps.Map(document.getElementById('map'), mapOptions);
        }
        function showStoresOnMap(stores) {
            pm.markers = [];
            var mapOptions = {
                zoom: 9,
                center: new google.maps.LatLng(stores[0].latitude, stores[0].longitude),
                mapTypeId: google.maps.MapTypeId.ROADMAP
            };
            pm.map = new google.maps.Map(document.getElementById('map'), mapOptions);
            var bounds = new google.maps.LatLngBounds();
            var infoWindow = new google.maps.InfoWindow();
            var pinImage = new google.maps.MarkerImage('/assets/theme/tfs/images/map-pin.png');
            angular.forEach(stores, function (store) {
                var latLng = new google.maps.LatLng(store.latitude, store.longitude);
                var marker = new google.maps.Marker({
                    map: pm.map,
                    position: latLng,
                    title: store.name,
                    icon: pinImage
                });
                marker.content = '<div class="infoWindowContent">' + store.name + '</div>';
                google.maps.event.addListener(marker, 'click', function () {
                    infoWindow.setContent('<h2>' + marker.title + '</h2>' + marker.content);
                    infoWindow.open(pm.map, marker);
                });

                bounds.extend(latLng);
                pm.markers.push(marker);
            });
            pm.map.fitBounds(bounds);
            pm.map.panToBounds(bounds);
            var listener = google.maps.event.addListener(pm.map, "idle", function () {
                pm.map.setZoom(9);
                google.maps.event.removeListener(listener);
            });
        }
        function getHtml(content) {
            return $sce.trustAsHtml(content);
        };
        function videoPopupModal() {
            $('#videoPopupModal').modal('show');
        }
        function deletedFromWishlist(productId) {
            $http.post("/TFSAccount/RemoveWishList", { id: productId }).then(function (resp) {
                pm.productModel = resp.data;
                pm.IsDeletedFromWishlist = true;
                $timeout(function () {
                    $(".deleteWishdiv").fadeOut();
                    pm.IsDeletedFromWishlist = false;
                }, 2000);
            }, function (error) { });
        }
        function getProductReview() {
            pm.model.reviews = [];
            if (pm.model.hideReviews) {
                return;
            }
            var stockCodes = [];
            stockCodes.push(pm.model.stockCode);
            if (pm.model.variantProducts != null && pm.model.variantProducts.length > 0) {
                angular.forEach(pm.model.variantProducts, function (variant) {
                    stockCodes.push(variant.stockCode);
                });
            }
            $http.post(productConfig.getProductReviewsUrl, stockCodes).success(function (resp) {
                if (resp != null) {
                    var ratingTotal = 0;
                    pm.reviews = resp;
                    pm.model.reviews = resp;
                    angular.forEach(pm.model.reviews, function (review) {
                        ratingTotal += review.rating.avgRating;
                    });
                    pm.productAvgRating = (ratingTotal / pm.model.reviews.length) * 20;
                }
            }, function (error) { });
        }

        function fetchMoreReviews(stocks) {
            $http.post("/TFSProduct/FetchMoreReviews", { currentPage: 1, stockCodes: stocks, pageSize: 100 }).success(function (resp) {
                $("#feefoReview").remove();
                $("#reviewContainer").append($(resp));
            });
        };



        function slugifyUrl(url) {
            url = url || '';
            return url.replace(/ /g, '-').toLowerCase();
        }

        function brandCarousels() {
            setTimeout(function () {
                if (typeof Swiper !== 'undefined') {
                    let spaceBetween = 30;
                    if (typeof luxuryTemplateV2 !== 'undefined' && luxuryTemplateV2 === true) {
                        spaceBetween = 10;
                    }
                    new Swiper('.swiper-container', {
                        slidesPerView: 2,
                        slidesPerGroup: 2,
                        spaceBetween: spaceBetween,
                        navigation: {
                            nextEl: '.swiper-button-next',
                            prevEl: '.swiper-button-prev',
                        },
                        observer: true,
                        observeParents: true,
                        breakpoints: {
                            768: {
                                slidesPerView: 3,
                                slidesPerGroup: 3,
                            },
                            992: {
                                slidesPerView: 4,
                                slidesPerGroup: 4,
                            },
                        }
                    });
                }
            }, 500);
        }

        function searchCollectionProducts(manufacturerSettings) {
            pm.collectionListTemp = [];
            angular.forEach(manufacturerSettings.split(','), function (value, key) {
                var resp = value.split(':');
                if (resp != null && resp[0].toLowerCase() != 'displayorder' && resp[0].toLowerCase() != 'morevideo') {
                    if (resp.length > 1) {
                        var tempData = resp[1].split('__');
                        var tempHeading = null;
                        if (tempData != null && tempData.length > 2) {
                            tempHeading = tempData[2];
                        }
                        if (tempData != null && tempData.length > 1) {
                            pm.collectionList.push({ key: resp[0], value: tempData[1], heading: tempHeading });
                            pm.collectionListTemp.push({ key: resp[0], value: tempData[1] });
                        }
                    }
                }
            });
            $http.post(productConfig.getCollectionProductsUrl, pm.collectionListTemp)
                .success(function (data) {
                    brandCarousels();
                    if (data != null) {
                        pm.collectionProuducts = data;
                        if (pm.collectionProuducts != null) {
                            angular.forEach(pm.collectionList, function (value, key) {
                                if (pm.collectionProuducts.bestseller != null && pm.collectionProuducts.bestseller.searchCriteria.collectionId.toLowerCase() == value.value.toLowerCase()) {
                                    pm.collectionProuducts.bestseller.heading = value.heading;
                                }
                                else if (pm.collectionProuducts.bestsellerwomen && pm.collectionProuducts.bestsellerwomen.searchCriteria.collectionId.toLowerCase() == value.value.toLowerCase()) {
                                    pm.collectionProuducts.bestsellerwomen.heading = value.heading;
                                }
                                else if (pm.collectionProuducts.bestsellermen && pm.collectionProuducts.bestsellermen.searchCriteria.collectionId.toLowerCase() == value.value.toLowerCase()) {
                                    pm.collectionProuducts.bestsellermen.heading = value.heading;
                                }
                                else if (pm.collectionProuducts.newrelease && pm.collectionProuducts.newrelease.searchCriteria.collectionId.toLowerCase() == value.value.toLowerCase()) {
                                    pm.collectionProuducts.newrelease.heading = value.heading;
                                }
                            });
                            var noOfItemInRow = 4;
                            if (window != null && window.innerWidth != null && window.innerWidth <= 767) {
                                noOfItemInRow = 2;
                            }
                            if (pm.collectionProuducts.bestsellerwomen != null && pm.collectionProuducts.bestsellerwomen.results != null) {
                                var tempCount = pm.collectionProuducts.bestsellerwomen.results.length / noOfItemInRow;
                                var tempList = [];
                                var tempCounter = 0;
                                var count = 0;
                                var tempArray = [];
                                var totalProcessedItem = 0;
                                angular.forEach(pm.collectionProuducts.bestsellerwomen.results, function (value, key) {

                                    tempArray.push(value);
                                    count = count + 1;
                                    totalProcessedItem = totalProcessedItem + 1;
                                });
                                pm.collectionProuducts.bestsellerwomen.productSet = tempArray;
                            }
                            if (pm.collectionProuducts.bestsellermen != null && pm.collectionProuducts.bestsellermen.results != null) {
                                var tempCount = pm.collectionProuducts.bestsellermen.results.length / noOfItemInRow;
                                var tempList = [];
                                var tempCounter = 0;
                                var count = 0;
                                var tempArray = [];
                                var totalProcessedItem = 0;
                                angular.forEach(pm.collectionProuducts.bestsellermen.results, function (value, key) {
                                    tempArray.push(value);
                                    count = count + 1;
                                    totalProcessedItem = totalProcessedItem + 1;
                                });
                                pm.collectionProuducts.bestsellermen.productSet = tempArray;
                            }
                        }
                    }
                })
                .error(function (msg) {
                })
                .finally(function () {
                    pm.currencyCookie = $.cookie(CURRENCYCOOKIE.CurrencyCode);
                    pm.changeBaseCurrency(pm.currencyCookie);
                });
        }

        function hideGiftCardMsg() {
            $timeout(function () {
                $(".giftCardMsg").fadeOut();
            }, 3000);
        }
        pm.showChangedCurrency = false;
        function changeBaseCurrency(changeToCurrencyCode) {
            if (pm.enableChangeBaseCurrencyV2 == 1) {
                $.cookie("basecurrencyv2", 1, { path: '/', expires: 1000 });
                return;
            }
            if ($.cookie('basecurrencyv2'))
                $.removeCookie('basecurrencyv2', { path: '/' });
            
            if (changeToCurrencyCode == null)
                changeToCurrencyCode = $.cookie(CURRENCYCOOKIE.CurrencyCode);
            if (changeToCurrencyCode) {
                $http.get(productConfig.currencyExchangeRate + "?changeToCurrencyCode=" + changeToCurrencyCode).then(function (resp) {
                    if (resp != null && resp.data != false && resp.data.rate != 1) {
                        pm.showChangedCurrency = true;
                        pm.selectedCurrencySymbol = resp.data.currencySymbol;
                        pm.currencyExchangeRate = resp.data.rate;
                        if (pm.productResponse != null && pm.productResponse.results) {
                            angular.forEach(pm.productResponse.results, function (product) {
                                product.currencyExchangedPriceRaw = product.price.raw.withTax * resp.data.rate;
                                product.currencyExchangedPriceFormatted = pm.selectedCurrencySymbol + product.currencyExchangedPriceRaw.toFixed(2);
                                product.currencyExchangedListPriceFormatted = pm.selectedCurrencySymbol + (product.listPrice.raw.withTax * resp.data.rate).toFixed(2);
                                product.currencyExchangedPriceFromFormatted = pm.selectedCurrencySymbol + (product.priceFrom.raw.withTax * resp.data.rate).toFixed(2);
                                product.currencyExchangedRRP = pm.selectedCurrencySymbol + ((product.listPrice.raw.withTax - product.price.raw.withTax) * resp.data.rate).toFixed(2);
                            });
                        }
                        if (pm.collectionProuducts != null && pm.collectionProuducts.bestsellerwomen != null && pm.collectionProuducts.bestsellerwomen.productSet != null) {
                            angular.forEach(pm.collectionProuducts.bestsellerwomen.productSet, function (prodSetWomen) {
                                angular.forEach(prodSetWomen.productsList, function (prodWomen) {
                                    prodWomen.currencyExchangedPriceFrom = pm.selectedCurrencySymbol + (prodWomen.priceFrom.raw.withTax * resp.data.rate).toFixed(2);
                                    prodWomen.currencyExchangedPrice = pm.selectedCurrencySymbol + (prodWomen.price.raw.withTax * resp.data.rate).toFixed(2);
                                    prodWomen.currencyExchangedListPriceFormatted = pm.selectedCurrencySymbol + (prodWomen.listPrice.raw.withTax * resp.data.rate).toFixed(2);
                                    prodWomen.currencyExchangedSavingFormatted = pm.selectedCurrencySymbol + ((prodWomen.listPrice.raw.withTax - prodWomen.price.raw.withTax) * resp.data.rate).toFixed(2);
                                });
                            });
                        }
                        if (pm.collectionProuducts != null && pm.collectionProuducts.bestsellermen != null && pm.collectionProuducts.bestsellermen.productSet != null) {
                            angular.forEach(pm.collectionProuducts.bestsellermen.productSet, function (prodSetMen) {
                                angular.forEach(prodSetMen.productsList, function (prodMen) {
                                    prodMen.currencyExchangedPriceFrom = pm.selectedCurrencySymbol + (prodMen.priceFrom.raw.withTax * resp.data.rate).toFixed(2);
                                    prodMen.currencyExchangedPrice = pm.selectedCurrencySymbol + (prodMen.price.raw.withTax * resp.data.rate).toFixed(2);
                                    prodMen.currencyExchangedListPriceFormatted = pm.selectedCurrencySymbol + (prodMen.listPrice.raw.withTax * resp.data.rate).toFixed(2);
                                    prodMen.currencyExchangedSavingFormatted = pm.selectedCurrencySymbol + ((prodMen.listPrice.raw.withTax - prodMen.price.raw.withTax) * resp.data.rate).toFixed(2);
                                });
                            });
                        }
                    }
                    else
                        pm.showChangedCurrency = false;
                    $.cookie("_ctcc", changeToCurrencyCode, { path: '/', expires: 1000 });
                }, function (error) {
                });
            }
        }

        function changeCurrecyValueForEngraving(priceWithEngraving) {
            if (pm.enableChangeBaseCurrencyV2 != 1) {
                var currencyCookie = $.cookie("_ctcc");
                var isSubscriptionEnabled = $(".subscriptionEnabled").val();
                if (currencyCookie != null && !isSubscriptionEnabled) {
                    $.get('/Home/GetCurrencyExchangeRate' + "?changeToCurrencyCode=" + currencyCookie, function (data) {
                        if (data != null && data != false && data.rate != 1) {
                            var engravingPrice = $(".proEngravingPriceRaw").val();
                            if (engravingPrice.length == 0 && pm.model.engravingProduct != null && pm.model.engravingProduct.length > 0) {
                                engravingPrice = pm.model.engravingProduct[0].price.raw.withTax;
                            }
                            var selectedCurrencyData = data;
                            var currencyExchangeEngravingPrice = selectedCurrencyData.currencySymbol + (engravingPrice * selectedCurrencyData.rate).toFixed(2);
                            var currencyEngravePriceExchangePrice = selectedCurrencyData.currencySymbol + (priceWithEngraving * selectedCurrencyData.rate).toFixed(2);
                            $(".engravePriceFormatted").html(currencyEngravePriceExchangePrice);
                            $(".proEngravingPriceFormatted").html(currencyExchangeEngravingPrice);
                        }
                    });
                }
            }
        }
    };
})();
;
$(".curated-collection-wrapper button").click(function () {
    $(this).addClass("pending");
    $(this).html("");
});;
(function () {
    'use strict';

    window.app.controller('subscriptionCtrl', subscriptionCtrl);
    window.app.constant('SUBSCRIPTION_CONSTANTS', {
        'SubscriptionPlanPricingType': {
            'Flat': 1,
            'Term': 2,
            'PerUnit': 3
        },
        'UserPricingType': {
            'None': "None",
            'OneTime': "OneTime",
            'Recurring': "Recurring"
        },
        'SubscriptionPlanType': {
            'Simple': "Simple",
            'FixedBundle': "FixedBundle",
            'DynamicBundle': "DynamicBundle"
        },
        'EMPTYGUID': '00000000-0000-0000-0000-000000000000'
    });
    subscriptionCtrl.$inject = ['$scope', '$http', 'globalConfig', 'SUBSCRIPTION_CONSTANTS'];
    function subscriptionCtrl($scope, $http, globalConfig, SUBSCRIPTION_CONSTANTS) {
        var sm = this;
        //Variables 
        sm.subscriptionPlan = {};

        //Methods declarations
        sm.initSubscriptionPlan = initSubscriptionPlan;
        sm.addSubscriptionToBasket = addSubscriptionToBasket;
        sm.isEmptyObj = isEmptyObj;


        //Method implementation
        function initSubscriptionPlan(productId) {
            getSubscriptionPlan(productId);
        }

        //fetch the subscription plan based on product id
        //used as helper method to get subscription plan.
        function getSubscriptionPlan(productId) {
            $http.get("/Subscription/GetSubscriptionPlan?productId=" + productId).then(function (success) {
                sm.subscriptionPlan = success.data.result;
                ////select default term and pricing. 
                //sm.subscriptionModel.selectedTerm = sm.subscriptionPlan.terms.find(i => i.isDefault);
                //sm.subscriptionModel.selectedPricing = SUBSCRIPTION_CONSTANTS.UserPricingType.Recurring;
            }, function (error) { });
        }

        function isEmptyObj(obj) {
            for (var prop in obj) {
                if (obj.hasOwnProperty(prop))
                    return false;
            }
            return true;
        };

        //
        function addSubscriptionToBasket(productId) {
            if (productId != null && productId != undefined && productId != SUBSCRIPTION_CONSTANTS.EMPTYGUID) {
                //check if subscription plan does exist in scope
                if (sm.isEmptyObj(sm.subscriptionPlan) || sm.subscriptionPlan == null || sm.subscriptionPlan == undefined)
                    getSubscriptionPlan(productId);

                //if (sm.currentSubscription != null && sm.currentSubscription.seedOrderDetail != null) {
                //    var orderLine = { productId: productId, id: SUBSCRIPTION_CONSTANTS.EMPTYGUID }
                //    $http.post("/account/UpsertSubscriptionOrderLine", { id: sm.currentSubscription.seedOrderDetail.companyOrderId, orderLine: orderLine }).success(function (resp) {
                //        if (resp) {
                //            window.location.href = '/myaccount/scent-addict/future-fragrances?pageName=FutureFragrance';
                //        }
                //    });
                //} else {
                var basketId = SUBSCRIPTION_CONSTANTS.EMPTYGUID;
                //prepare add subscription to basket model.
                if ($scope.$parent.$parent.gm != undefined && typeof $scope.$parent.$parent.gm.basketResponse != typeof undefined && $scope.$parent.$parent.gm.basketResponse != null) {
                    basketId = $scope.$parent.$parent.gm.basketResponse.id;
                } else if ($scope.$parent.gm != undefined && typeof $scope.$parent.gm.basketResponse != typeof undefined && $scope.$parent.gm.basketResponse != null) {
                    //this condition is used when the function is called from recommendation directive
                    //there we have only two levels of nested scope not three level. 
                    basketId = $scope.$parent.gm.basketResponse.id;
                }
                if (basketId == null || basketId == undefined) {
                    basketId = SUBSCRIPTION_CONSTANTS.EMPTYGUID;
                }
                var model = {
                    productId: productId, basketId: basketId, subscriptionPlanId: sm.subscriptionPlan.recordId, qty: 1, isSubscription: true
                };
                //add to basket api call
                $http.post(globalConfig.addToBasket, model)
                    .success(function (data) {
                        if (data.activeSubscription && data.messageCode != 'C002') {
                            // if user has added a single product after reactivation reset the cookie. 
                            if ($.cookie('isnewlist'))
                                $.removeCookie('isnewlist', { path: '/' })

                            window.location.href = '/myaccount/scentaddict/your-list';
                        } else {
                            if ($scope.$parent.$parent.gm != undefined) {
                                $scope.$parent.$parent.gm.initBasket(data.result);
                            } else {
                                $scope.gm.initBasket(data.result);
                            }
                            //update basket

                            extractSubscriptionItems(data.result.lineItems);

                            if (data.messageCode != 'C002') {
                                if ($scope.$parent.$parent.gm != undefined && $scope.$parent.$parent.gm.basketResponse != null && $scope.$parent.$parent.gm.basketResponse != undefined && $scope.$parent.$parent.gm.basketResponse.lineItems != null && $scope.$parent.$parent.gm.basketResponse.lineItems.length > 0) {
                                    //get the last added item sub-brand 
                                    var lastAddedItem = null;
                                    angular.forEach($scope.$parent.$parent.gm.basketResponse.lineItems, function (value) {
                                        if (lastAddedItem == null && value.productId.toLowerCase() == productId.toLowerCase()) {
                                            lastAddedItem = value;
                                        }
                                    });

                                    if (lastAddedItem) {
                                        //store sub-brand in cookie
                                        $.cookie("_sbn", lastAddedItem.subbrand, { path: '/' });

                                        //redirect to offer page
                                        if ($scope.$parent.$parent.gm.offerCategoryName != null && $scope.$parent.$parent.gm.offerCategoryName != "")
                                            window.location.href = globalConfig.offerUrl + "/?categoryType=" + $scope.$parent.$parent.gm.offerCategoryName;
                                        else
                                            window.location.href = globalConfig.offerUrl;

                                    }
                                }
                            }

                        }
                    })
                    .error(function (msg) {

                    })
                    .finally(function () {

                    });
                //}
            }
        }


        //Re-arrange subscription lines
        function extractSubscriptionItems(basketItems) {
            var subscriptionItems = [];
            if (basketItems != null && basketItems != undefined && basketItems.length > 0) {
                angular.forEach(basketItems, function (item) {
                    if (item.subscriptionUserSettings.subscriptionPlanId == sm.subscriptionPlan.recordId) {
                        subscriptionItems.push(item);
                    }
                });
            }

        }



    }





})();
;
(function () {
    'use strict';
    window.app.controller('giftCardVirtualCtrl', giftCardVirtualCtrl);
    giftCardVirtualCtrl.$inject = ['$scope', '$http', 'globalConfig', 'alerts'];
    function giftCardVirtualCtrl($scope, $http, globalConfig, alerts) {
        var sm = this;
        //Variables 
        sm.empGuid = '00000000-0000-0000-0000-000000000000';

        //Methods declarations
        sm.addGiftToBasket = addGiftToBasket;

        //
        function addGiftToBasket(productId) {
            if (productId != null && productId != undefined) {
                //check if subscription plan does exist in scope
                var basketId = sm.empGuid;
                //prepare add subscription to basket model.
                if ($scope.$parent.$parent.gm != undefined && typeof $scope.$parent.$parent.gm.basketResponse != typeof undefined && $scope.$parent.$parent.gm.basketResponse != null) {
                    basketId = $scope.$parent.$parent.gm.basketResponse.id;
                } else if ($scope.$parent.gm != undefined && typeof $scope.$parent.gm.basketResponse != typeof undefined && $scope.$parent.gm.basketResponse != null) {
                    //this condition is used when the function is called from recommendation directive
                    //there we have only two levels of nested scope not three level. 
                    basketId = $scope.$parent.gm.basketResponse.id;
                }
                if (basketId == null || basketId == undefined) {
                    basketId = sm.empGuid;
                }
                var model = {
                    productId: productId, basketId: basketId, qty: 1, itemGroupId: 7
                };
                //add to basket api call
                $http.post(globalConfig.addToBasket, model)
                    .success(function (data) {
                        if (data != null && data.isValid == false) {
                            alerts.error(data.message);
                        } else {
                            window.location.href = '/checkout/payment/' + data.result.id;
                        }
                    })
                    .error(function (msg) {

                    })
                    .finally(function () {

                    });
                //}
            }
        }
    }
})();;
/**
 * @license angular-recaptcha build:2018-07-30
 * https://github.com/vividcortex/angular-recaptcha
 * Copyright (c) 2018 VividCortex
**/


!function (a) { "use strict"; a.module("vcRecaptcha", []) }(angular), function (a) { "use strict"; function b() { throw new Error('You need to set the "key" attribute to your public reCaptcha key. If you don\'t have a key, please get one from https://www.google.com/recaptcha/admin/create') } a.module("vcRecaptcha").provider("vcRecaptchaService", function () { var c = this, d = {}; c.onLoadFunctionName = "vcRecaptchaApiLoaded", c.setDefaults = function (b) { a.copy(b, d) }, c.setSiteKey = function (a) { d.key = a }, c.setTheme = function (a) { d.theme = a }, c.setStoken = function (a) { d.stoken = a }, c.setSize = function (a) { d.size = a }, c.setType = function (a) { d.type = a }, c.setLang = function (a) { d.lang = a }, c.setBadge = function (a) { d.badge = a }, c.setOnLoadFunctionName = function (a) { c.onLoadFunctionName = a }, c.$get = ["$rootScope", "$window", "$q", "$document", "$interval", function (e, f, g, h, i) { function j() { return m ? g.when(m) : o } function k() { if (!m) throw new Error("reCaptcha has not been loaded yet.") } function l() { return a.isFunction((f.grecaptcha || {}).render) } var m, n = g.defer(), o = n.promise, p = {}; f.vcRecaptchaApiLoadedCallback = f.vcRecaptchaApiLoadedCallback || []; var q = function () { m = f.grecaptcha, n.resolve(m) }; if (f.vcRecaptchaApiLoadedCallback.push(q), f[c.onLoadFunctionName] = function () { f.vcRecaptchaApiLoadedCallback.forEach(function (a) { a() }) }, l()) q(); else if (f.document.querySelector('script[src^="https://www.google.com/recaptcha/api.js"]')) var r = i(function () { l() && (i.cancel(r), q()) }, 25); else { var s = f.document.createElement("script"); s.async = !0, s.defer = !0, s.src = "https://www.google.com/recaptcha/api.js?onload=" + c.onLoadFunctionName + "&render=explicit", h.find("body")[0].appendChild(s) } return { create: function (a, c) { return c.sitekey = c.key || d.key, c.theme = c.theme || d.theme, c.stoken = c.stoken || d.stoken, c.size = c.size || d.size, c.type = c.type || d.type, c.hl = c.lang || d.lang, c.badge = c.badge || d.badge, c.sitekey || b(), j().then(function (b) { var d = b.render(a, c); return p[d] = a, d }) }, reload: function (a) { k(), m.reset(a), e.$broadcast("reCaptchaReset", a) }, execute: function (a) { k(), m.execute(a) }, useLang: function (a, b) { var c = p[a]; if (!c) throw new Error("reCaptcha Widget ID not exists", a); var d = c.querySelector("iframe"); if (!b) return d && d.src && /[?&]hl=\w+/.test(d.src) ? d.src.replace(/.+[?&]hl=(\w+)([^\w].+)?/, "$1") : null; if (d && d.src) { var e = d.src; /[?&]hl=/.test(e) ? e = e.replace(/([?&]hl=)\w+/, "$1" + b) : e += (-1 === e.indexOf("?") ? "?" : "&") + "hl=" + b, d.src = e } }, getResponse: function (a) { return k(), m.getResponse(a) }, getInstance: function (a) { return p[a] }, destroy: function (a) { delete p[a] } } }] }) }(angular), function (a) { "use strict"; a.module("vcRecaptcha").directive("vcRecaptcha", ["$document", "$timeout", "vcRecaptchaService", function (b, c, d) { return { restrict: "A", require: "?^^form", scope: { response: "=?ngModel", key: "=?", stoken: "=?", theme: "=?", size: "=?", type: "=?", lang: "=?", badge: "=?", tabindex: "=?", required: "=?", onCreate: "&", onSuccess: "&", onExpire: "&", onError: "&" }, link: function (e, f, g, h) { function i() { h && h.$setValidity("recaptcha", null), m() } function j() { c(function () { e.response = "", l(), e.onExpire({ widgetId: e.widgetId }) }) } function k() { var a = arguments; c(function () { e.response = "", l(), e.onError({ widgetId: e.widgetId, arguments: a }) }) } function l() { h && h.$setValidity("recaptcha", !1 === e.required ? null : Boolean(e.response)) } function m() { d.destroy(e.widgetId), a.element(b[0].querySelectorAll(".pls-container")).parent().remove() } e.widgetId = null, h && a.isDefined(g.required) && e.$watch("required", l); var n = e.$watch("key", function (b) { var h = function (a) { c(function () { e.response = a, l(), e.onSuccess({ response: a, widgetId: e.widgetId }) }) }; d.create(f[0], { callback: h, key: b, stoken: e.stoken || g.stoken || null, theme: e.theme || g.theme || null, type: e.type || g.type || null, lang: e.lang || g.lang || null, tabindex: e.tabindex || g.tabindex || null, size: e.size || g.size || null, badge: e.badge || g.badge || null, "expired-callback": j, "error-callback": g.onError ? k : void 0 }).then(function (b) { l(), e.widgetId = b, e.onCreate({ widgetId: b }), e.$on("$destroy", i), e.$on("reCaptchaReset", function (c, d) { (a.isUndefined(d) || b === d) && (e.response = "", l()) }) }), n() }) } } }]) }(angular);;
