(function () {
    'use strict';
    /* Initialize the main module */
    var Xapp = angular.module('btApp', ['bw.paging', 'btAutoComplete', 'CapturePlus', 'ui.sortable', 'ordinal', 'btImageUtil', 'btimageutilcustom', 'btRecommendation']);

    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="">' +
                    '<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-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 = 3;
                    $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.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) {
                        if (eventData != null && dataLayer && 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 (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)" srcset="{{imageUrl}}?h={{imageUtil.HiRes_H}}&w={{imageUtil.HiRes_W}}&min-w={{imageUtil.HiRes_W}}&min-h={{imageUtil.HiRes_H}}"> ' +
                ' <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}}"> ' +
                ' <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}}"> ' +
                ' <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}}"> ' +
                ' <img ng-src="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}&min-w={{imageUtil.Mobile_W}}&min-h={{imageUtil.Mobile_H}}" alt="{{itemName}}" class="image1 omni-img">' +
                '</picture> ' +
                '<img  ng-if="imageUrl==\'\'" src="/assets/theme/tfs/images/noimagefound.jpg"  alt="{{itemName}}" class="img-responsive omni-img"/ >', 
                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('btimageutilcustom', [])
        .directive('btimageutilcustom', function ($parse, $http, $sce) {
            return {
                restrict: 'A',               
                template: '<picture> ' +
                ' <source media="(min-width: 1440px)" srcset="{{imageUrl}}?h={{imageUtil.HiRes_H}}&w={{imageUtil.HiRes_W}}"> ' + 
                            ' <source media="(min-width: 1200px)" srcset="{{imageUrl}}?h={{imageUtil.Desktop_H}}&w={{imageUtil.Desktop_W}}"> ' + 
                            ' <source media="(min-width: 768px)" srcset="{{imageUrl}}?h={{imageUtil.Tablet_H}}&w={{imageUtil.Tablet_W}}"> ' + 
                            ' <source media="(min-width: 480px)" srcset="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}"> ' + 
                            ' <img ng-src="{{imageUrl}}?h={{imageUtil.Mobile_H}}&w={{imageUtil.Mobile_W}}" alt="{{itemName}}" class="image1 omni-img">' + 
                           '</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('btRecommendation', [])
        .directive('btRecommendation', function ($parse, $http, $sce, $timeout) {
            return {
                restrict: 'EA',
                scope: {
                    "itemId": "@itemid",
                    "userId": "@userid",
                    "type": "@type",
                    "title": "@title",
                    "noOfItems": "@noofitems"
                },
                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 class="ng-binding" ng-bind="prod.price.formatted.withTax"></span> ' +
                '<span class="sml ng-binding" ng-bind="prod.listPrice.formatted.withTax"></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" ng-click="gm.offerCategoryName=prod.classification.mainCategoryName;gm.addToBasket(prod.recordId,1,0)">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" ng-click="gm.offerCategoryName=prod.classification.mainCategoryName;sm.addSubscriptionToBasket(prod.recordId)">Add To Scentaddict List</button >' +
                '</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 RECENT_PRODUCT_COOKIE = '_rvp';
                    $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;
                    }).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';
    /* 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: companynameid, field: 'Company' },
                { 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';

    window.app.constant('REGEX_CONSTANTS', {
        'LETTERS_AND_NUMBERS_ONLY': '^[a-zA-Z0-9 ]+$',
    });
})();;
(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'
    });
    // 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'];

    function globalCtrl($scope, $timeout, globalConfig, $http, loader, CapturePlus, scriptLoader, BULKORDER_CONSTANTS, Recommendation, PERSONALISATION, REGEX_CONSTANTS, alerts) {
        var gm = this;
        gm.model = {};

        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.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;

        //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.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.activeClass = '';

        //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.selectedLineItem = {};
        gm.isGiftWrapApplied = false;
        gm.giftWrapError = false;
        gm.addGiftButtonClicked = false;
        gm.addGiftWrap = addGiftWrap;
        gm.checkGiftWrap = checkGiftWrap;
        gm.removeGiftWrap = removeGiftWrap;
        gm.updateBasketBadgeCount = updateBasketBadgeCount;

        /*******below code is for recomendation**********/
        gm.recomendations = {};
        gm.openGiftModal = openGiftModal;
        // 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;

        //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. 
                console.log(gm.subscriptionItems);

            },
            stop: function (e, ui) {
                //perform after sort math. 
                console.log(gm.subscriptionItems);
                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) {

            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) {
                    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;
                    initBasket(dataResult);
                })
                    .error(function (msg) {
                        if (msg.errorMessage != "false") {
                            gm.showCustomMsg = true;
                            gm.customMsg = msg.errorMessage;
                        }
                        gm.invalidpromo = true;
                        $('.promo').show(0).delay(2000).hide(0);
                    })
                    .finally(function () {
                    });
            } else {
                gm.promonull = true;
                $('.promonull').show(0).delay(1200).hide(0);
            }
        }

        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) {
            if (basket == null || basket == undefined) {
                if (gm.basketResponse == null || gm.basketResponse == undefined) {
                    $http.post(globalConfig.getBasketUrl)
                        .success(function (data) {
                            gm.basketResponse = data;
                            initAddToBagQty();
                            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;
                                extractSubscription();
                                extractCustomInfo(gm.basketResponse);
                                updateBasketBadgeCount();
                            }

                        })
                        .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);
                                }
                            });
                        }
                    });
                    initAddToBagQty();
                    gm.count = gm.basketResponse.lineItemCount;
                    gm.postCode = $.cookie(BULKORDER_CONSTANTS.POSTCODE);
                }
            }
        }

        //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);
                }
            }
        }

        function addLookbookToCart(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);
            });
        }

        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) {
            if (isSubscription == undefined)
                isSubscription = false;
            if ($scope.addToBagInProgress) {
                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 prod = {
                "basketId": basketId,
                "productId": recordId,
                "qty": qty,
                "displayOrder": gm.displayOrder,
                "itemType": itemType,
                "issubscription": isSubscription
            };
            //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 
                            }
                        });
                        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);
                            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;
                                        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"
                                    ]);
                                }
                            }
                        }
                    }
                    //redirect to offer page
                    if (data.messageCode != 'C002' || gm.isProductExist || gm.engravingFailedAction === 'continue') {
                        if (gm.isProductExist) {
                            $timeout(function () {
                                redirectToOffers(recordId, isAlreadyExistInBasket);
                            }, 3000);
                        } else {
                            redirectToOffers(recordId, isAlreadyExistInBasket);
                        }
                        gm.isProductExist = false;
                    }

                    //engraving failed modal actions
                    if (gm.engravingFailedAction === 'remove' && gm.engravingProduct) {
                        engravingFiledActions();
                    }

                })
                .error(function (msg) {

                })
                .finally(function () {

                });
        };

        function redirectToOffers(productId, isAlreadyExistInBasket) {
            if (!isAlreadyExistInBasket || gm.engravingFailedAction === 'continue') {
                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) {
            $http.post(globalConfig.removePromoCode, {id: id, promoCode: promoCode})
                .success(function (data) {
                    var dataResult = gm.serializedData(data.result.basket);
                    gm.basketResponse = dataResult;
                    initBasket(dataResult);
                })
                .error(function (msg) {
                })
                .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

        function userLogin(model) {
            gm.saving = false;
            gm.errorMessage = null;
            gm.success = false;
            $(".alertBlock").hide();
            $http.post(globalConfig.signIn, 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)
                            window.location.reload();
                        else
                            window.location.href = window.location.origin + '/myaccount';
                    }
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    gm.saving = false;
                    gm.signing = false;
                });
        }

        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
                            window.location.href = "/MyAccount";
                    }
                })
                .error(function (msg) {
                    gm.errorMessage = msg.errorMessages;
                })
                .finally(function () {
                    gm.registering = false;
                });

            if (!gm.model.registerViewModel.notifyNone && (gm.model.registerViewModel.notifyByEmail || gm.model.registerViewModel.notifyByPost || gm.model.registerViewModel.notifyBySMS)) {
                var newsletterModel = {
                    Email: gm.model.registerViewModel.email,
                    notifyByEmail: gm.model.registerViewModel.notifyByEmail,
                    notifyBySMS: gm.model.registerViewModel.notifyBySMS,
                    notifyByPost: gm.model.registerViewModel.notifyByPost
                };
                $http.post(globalConfig.newsLetterSubscription, newsletterModel).then(function (success) {
                }, function (error) {
                });
            }
        }

        function login(model) {
            $scope.signin = true;
            gm.signing = true;
            $scope.register = false;
            $scope.global_login = false;
            gm.userLogin(model);
        }

        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}
            if (gm.emailinvalid == false) {
                $http.post(globalConfig.newsLetterSubscription, {newsletter: model})
                    .success(function (data) {
                        gm.customerEmail = '';
                        if (data == true) {
                            gm.subssuccess = true;
                            $('.newslettersuccess').show(0).delay(5000).hide(0);

                            $.cookie("NewsLetterSubscribed", email, {path: '/', expires: 1000});
                            gm.isNewsLetterSubscribed = $.cookie("NewsLetterSubscribed");
                            //$timeout(function () {
                            //    gm.isValiduser = false;
                            //    gm.isValid = false;
                            //    window.location.reload();
                            //}, 3000);
                        } 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 && 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(isSelected) {
            if (isSelected) {
                $("#giftChoose").modal('show').on('hide.bs.modal', function () {
                    checkGiftWrap();
                    $("#giftChoose").off('hide.bs.modal');
                });
            }
        }

        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)
                    var 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) {
                $http.post("/TFSBasket/SavePersonalisationInfo", {
                    basketResp: data.result,
                    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);
                });
            }
        }

        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;
            gm.basketResponse = data.result;
            //reset giftwarp options
            if (giftWrapOption && data.result.giftWrapOption === null) {
                gm.basketResponse.giftWrapOption = giftWrapOption;
            }
            //var count = 0;
            if (gm.basketResponse != null) {
                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);
                                }
                            });
                        }
                        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();
                }
                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);
                }

                //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 (selectedGiftOption != null && Object.keys(selectedGiftOption) != 0) {
                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) {
                    $("#giftChoose").modal('hide');
                    gm.selectedGiftWrapOption = {};
                    //assign updated basket. 
                    updateBasket(success.data);
                    gm.addGiftButtonClicked = false;
                }, function (error) {
                });
            } else {
                gm.giftWrapError = true;
                gm.addGiftButtonClicked = false;
                $timeout(function () {
                    gm.giftWrapError = false;
                }, 10000);
            }
        }

        //Remove gift wrapping
        function removeGiftWrap(selectedGiftOption) {
            if (selectedGiftOption != null) {
                var model = {
                    basketId: gm.basketResponse.id,
                    productId: selectedGiftOption.productId,
                    stockCode: selectedGiftOption.stockCode,
                    Qty: 0,
                    isGiftWrapApplied: false,
                    parentProductId: gm.selectedLineItem.productId,
                    itemType: selectedGiftOption.itemType
                }
                $http.post("/Basket/RemoveGiftWrap", {model: model}).then(function (success) {
                    $("#giftChoose").modal('hide');
                    gm.selectedGiftWrapOption = {};
                    //assign updated basket. 
                    updateBasket(success.data);
                }, function (error) {
                });
            } 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 () {
                });
        };

    };
})();
;
(function ($, undefined) {
    'use strict';
    var defaults = {
        item: 3,
        autoWidth: false,
        slideMove: 1,
        slideMargin: 10,
        addClass: '',
        mode: 'slide',
        useCSS: true,
        cssEasing: 'ease', //'cubic-bezier(0.25, 0, 0.25, 1)',
        easing: 'linear', //'for jquery animation',//
        speed: 400, //ms'
        auto: false,
        pauseOnHover: false,
        loop: false,
        slideEndAnimation: true,
        pause: 2000,
        keyPress: false,
        controls: true,
        prevHtml: '',
        nextHtml: '',
        rtl: false,
        adaptiveHeight: false,
        vertical: false,
        verticalHeight: 500,
        vThumbWidth: 100,
        thumbItem: 10,
        pager: true,
        gallery: false,
        galleryMargin: 5,
        thumbMargin: 5,
        currentPagerPosition: 'middle',
        enableTouch: true,
        enableDrag: true,
        freeMove: true,
        swipeThreshold: 40,
        responsive: [],
        /* jshint ignore:start */
        onBeforeStart: function ($el) {},
        onSliderLoad: function ($el) {},
        onBeforeSlide: function ($el, scene) {},
        onAfterSlide: function ($el, scene) {},
        onBeforeNextSlide: function ($el, scene) {},
        onBeforePrevSlide: function ($el, scene) {}
        /* jshint ignore:end */
    };
    $.fn.lightSlider = function (options) {
        if (this.length === 0) {
            return this;
        }

        if (this.length > 1) {
            this.each(function () {
                $(this).lightSlider(options);
            });
            return this;
        }

        var plugin = {},
            settings = $.extend(true, {}, defaults, options),
            settingsTemp = {},
            $el = this;
        plugin.$el = this;

        if (settings.mode === 'fade') {
            settings.vertical = false;
        }
        var $children = $el.children(),
            windowW = $(window).width(),
            breakpoint = null,
            resposiveObj = null,
            length = 0,
            w = 0,
            on = false,
            elSize = 0,
            $slide = '',
            scene = 0,
            property = (settings.vertical === true) ? 'height' : 'width',
            gutter = (settings.vertical === true) ? 'margin-bottom' : 'margin-right',
            slideValue = 0,
            pagerWidth = 0,
            slideWidth = 0,
            thumbWidth = 0,
            interval = null,
            isTouch = ('ontouchstart' in document.documentElement);
        var refresh = {};

        refresh.chbreakpoint = function () {
            windowW = $(window).width();
            if (settings.responsive.length) {
                var item;
                if (settings.autoWidth === false) {
                    item = settings.item;
                }
                if (windowW < settings.responsive[0].breakpoint) {
                    for (var i = 0; i < settings.responsive.length; i++) {
                        if (windowW < settings.responsive[i].breakpoint) {
                            breakpoint = settings.responsive[i].breakpoint;
                            resposiveObj = settings.responsive[i];
                        }
                    }
                }
                if (typeof resposiveObj !== 'undefined' && resposiveObj !== null) {
                    for (var j in resposiveObj.settings) {
                        if (resposiveObj.settings.hasOwnProperty(j)) {
                            if (typeof settingsTemp[j] === 'undefined' || settingsTemp[j] === null) {
                                settingsTemp[j] = settings[j];
                            }
                            settings[j] = resposiveObj.settings[j];
                        }
                    }
                }
                if (!$.isEmptyObject(settingsTemp) && windowW > settings.responsive[0].breakpoint) {
                    for (var k in settingsTemp) {
                        if (settingsTemp.hasOwnProperty(k)) {
                            settings[k] = settingsTemp[k];
                        }
                    }
                }
                if (settings.autoWidth === false) {
                    if (slideValue > 0 && slideWidth > 0) {
                        if (item !== settings.item) {
                            scene = Math.round(slideValue / ((slideWidth + settings.slideMargin) * settings.slideMove));
                        }
                    }
                }
            }
        };

        refresh.calSW = function () {
            if (settings.autoWidth === false) {
                slideWidth = (elSize - ((settings.item * (settings.slideMargin)) - settings.slideMargin)) / settings.item;
            }
        };

        refresh.calWidth = function (cln) {
            var ln = cln === true ? $slide.find('.lslide').length : $children.length;
            if (settings.autoWidth === false) {
                w = ln * (slideWidth + settings.slideMargin);
            } else {
                w = 0;
                for (var i = 0; i < ln; i++) {
                    w += (parseInt($children.eq(i).width()) + settings.slideMargin);
                }
            }
            return w;
        };
        plugin = {
            doCss: function () {
                var support = function () {
                    var transition = ['transition', 'MozTransition', 'WebkitTransition', 'OTransition', 'msTransition', 'KhtmlTransition'];
                    var root = document.documentElement;
                    for (var i = 0; i < transition.length; i++) {
                        if (transition[i] in root.style) {
                            return true;
                        }
                    }
                };
                if (settings.useCSS && support()) {
                    return true;
                }
                return false;
            },
            keyPress: function () {
                if (settings.keyPress) {
                    $(document).on('keyup.lightslider', function (e) {
                        if (!$(':focus').is('input, textarea')) {
                            if (e.preventDefault) {
                                e.preventDefault();
                            } else {
                                e.returnValue = false;
                            }
                            if (e.keyCode === 37) {
                                $el.goToPrevSlide();
                            } else if (e.keyCode === 39) {
                                $el.goToNextSlide();
                            }
                        }
                    });
                }
            },
            controls: function () {
                if (settings.controls) {
                    $el.after('<div class="lSAction"><a class="lSPrev">' + settings.prevHtml + '</a><a class="lSNext">' + settings.nextHtml + '</a></div>');
                    if (!settings.autoWidth) {
                        if (length <= settings.item) {
                            $slide.find('.lSAction').hide();
                        }
                    } else {
                        if (refresh.calWidth(false) < elSize) {
                            $slide.find('.lSAction').hide();
                        }
                    }
                    $slide.find('.lSAction a').on('click', function (e) {
                        if (e.preventDefault) {
                            e.preventDefault();
                        } else {
                            e.returnValue = false;
                        }
                        if ($(this).attr('class') === 'lSPrev') {
                            $el.goToPrevSlide();
                        } else {
                            $el.goToNextSlide();
                        }
                        return false;
                    });
                }
            },
            initialStyle: function () {
                var $this = this;
                if (settings.mode === 'fade') {
                    settings.autoWidth = false;
                    settings.slideEndAnimation = false;
                }
                if (settings.auto) {
                    settings.slideEndAnimation = false;
                }
                if (settings.autoWidth) {
                    settings.slideMove = 1;
                    settings.item = 1;
                }
                if (settings.loop) {
                    settings.slideMove = 1;
                    settings.freeMove = false;
                }
                settings.onBeforeStart.call(this, $el);
                refresh.chbreakpoint();
                $el.addClass('lightSlider').wrap('<div class="lSSlideOuter ' + settings.addClass + '"><div class="lSSlideWrapper"></div></div>');
                $slide = $el.parent('.lSSlideWrapper');
                if (settings.rtl === true) {
                    $slide.parent().addClass('lSrtl');
                }
                if (settings.vertical) {
                    $slide.parent().addClass('vertical');
                    elSize = settings.verticalHeight;
                    $slide.css('height', elSize + 'px');
                } else {
                    elSize = $el.outerWidth();
                }
                $children.addClass('lslide');
                if (settings.loop === true && settings.mode === 'slide') {
                    refresh.calSW();
                    refresh.clone = function () {
                        if (refresh.calWidth(true) > elSize) {
                            /**/
                            var tWr = 0,
                                tI = 0;
                            for (var k = 0; k < $children.length; k++) {
                                tWr += (parseInt($el.find('.lslide').eq(k).width()) + settings.slideMargin);
                                tI++;
                                if (tWr >= (elSize + settings.slideMargin)) {
                                    break;
                                }
                            }
                            var tItem = settings.autoWidth === true ? tI : settings.item;

                            /**/
                            if (tItem < $el.find('.clone.left').length) {
                                for (var i = 0; i < $el.find('.clone.left').length - tItem; i++) {
                                    $children.eq(i).remove();
                                }
                            }
                            if (tItem < $el.find('.clone.right').length) {
                                for (var j = $children.length - 1; j > ($children.length - 1 - $el.find('.clone.right').length); j--) {
                                    scene--;
                                    $children.eq(j).remove();
                                }
                            }
                            /**/
                            for (var n = $el.find('.clone.right').length; n < tItem; n++) {
                                $el.find('.lslide').eq(n).clone().removeClass('lslide').addClass('clone right').appendTo($el);
                                scene++;
                            }
                            for (var m = $el.find('.lslide').length - $el.find('.clone.left').length; m > ($el.find('.lslide').length - tItem); m--) {
                                $el.find('.lslide').eq(m - 1).clone().removeClass('lslide').addClass('clone left').prependTo($el);
                            }
                            $children = $el.children();
                        } else {
                            if ($children.hasClass('clone')) {
                                $el.find('.clone').remove();
                                $this.move($el, 0);
                            }
                        }
                    };
                    refresh.clone();
                }
                refresh.sSW = function () {
                    length = $children.length;
                    if (settings.rtl === true && settings.vertical === false) {
                        gutter = 'margin-left';
                    }
                    if (settings.autoWidth === false) {
                        $children.css(property, slideWidth + 'px');
                    }
                    $children.css(gutter, settings.slideMargin + 'px');
                    w = refresh.calWidth(false);
                    $el.css(property, w + 'px');
                    if (settings.loop === true && settings.mode === 'slide') {
                        if (on === false) {
                            scene = $el.find('.clone.left').length;
                        }
                    }
                };
                refresh.calL = function () {
                    $children = $el.children();
                    length = $children.length;
                };
                if (this.doCss()) {
                    $slide.addClass('usingCss');
                }
                refresh.calL();
                if (settings.mode === 'slide') {
                    refresh.calSW();
                    refresh.sSW();
                    if (settings.loop === true) {
                        slideValue = $this.slideValue();
                        this.move($el, slideValue);
                    }
                    if (settings.vertical === false) {
                        this.setHeight($el, false);
                    }

                } else {
                    this.setHeight($el, true);
                    $el.addClass('lSFade');
                    if (!this.doCss()) {
                        $children.fadeOut(0);
                        $children.eq(scene).fadeIn(0);
                    }
                }
                if (settings.loop === true && settings.mode === 'slide') {
                    $children.eq(scene).addClass('active');
                } else {
                    $children.first().addClass('active');
                }
            },
            pager: function () {
                var $this = this;
                refresh.createPager = function () {
                    thumbWidth = (elSize - ((settings.thumbItem * (settings.thumbMargin)) - settings.thumbMargin)) / settings.thumbItem;
                    var $children = $slide.find('.lslide');
                    var length = $slide.find('.lslide').length;
                    var i = 0,
                        pagers = '',
                        v = 0;
                    for (i = 0; i < length; i++) {
                        if (settings.mode === 'slide') {
                            // calculate scene * slide value
                            if (!settings.autoWidth) {
                                v = i * ((slideWidth + settings.slideMargin) * settings.slideMove);
                            } else {
                                v += ((parseInt($children.eq(i).width()) + settings.slideMargin) * settings.slideMove);
                            }
                        }
                        var thumb = $children.eq(i * settings.slideMove).attr('data-thumb');
                        if (settings.gallery === true) {
                            pagers += '<li style="width:100%;' + property + ':' + thumbWidth + 'px;' + gutter + ':' + settings.thumbMargin + 'px"><a href="#"><img src="' + thumb + '" /></a></li>';
                        } else {
                            pagers += '<li><a href="#">' + (i + 1) + '</a></li>';
                        }
                        if (settings.mode === 'slide') {
                            if ((v) >= w - elSize - settings.slideMargin) {
                                i = i + 1;
                                var minPgr = 2;
                                if (settings.autoWidth) {
                                    pagers += '<li><a href="#">' + (i + 1) + '</a></li>';
                                    minPgr = 1;
                                }
                                if (i < minPgr) {
                                    pagers = null;
                                    $slide.parent().addClass('noPager');
                                } else {
                                    $slide.parent().removeClass('noPager');
                                }
                                break;
                            }
                        }
                    }
                    var $cSouter = $slide.parent();
                    $cSouter.find('.lSPager').html(pagers); 
                    if (settings.gallery === true) {
                        if (settings.vertical === true) {
                            // set Gallery thumbnail width
                            $cSouter.find('.lSPager').css('width', settings.vThumbWidth + 'px');
                        }
                        pagerWidth = (i * (settings.thumbMargin + thumbWidth)) + 0.5;
                        $cSouter.find('.lSPager').css({
                            property: pagerWidth + 'px',
                            'transition-duration': settings.speed + 'ms'
                        });
                        if (settings.vertical === true) {
                            $slide.parent().css('padding-right', (settings.vThumbWidth + settings.galleryMargin) + 'px');
                        }
                        $cSouter.find('.lSPager').css(property, pagerWidth + 'px');
                    }
                    var $pager = $cSouter.find('.lSPager').find('li');
                    $pager.first().addClass('active');
                    $pager.on('click', function () {
                        if (settings.loop === true && settings.mode === 'slide') {
                            scene = scene + ($pager.index(this) - $cSouter.find('.lSPager').find('li.active').index());
                        } else {
                            scene = $pager.index(this);
                        }
                        $el.mode(false);
                        if (settings.gallery === true) {
                            $this.slideThumb();
                        }
                        return false;
                    });
                };
                if (settings.pager) {
                    var cl = 'lSpg';
                    if (settings.gallery) {
                        cl = 'lSGallery';
                    }
                    $slide.after('<ul class="lSPager ' + cl + '"></ul>');
                    var gMargin = (settings.vertical) ? 'margin-left' : 'margin-top';
                    $slide.parent().find('.lSPager').css(gMargin, settings.galleryMargin + 'px');
                    refresh.createPager();
                }

                setTimeout(function () {
                    refresh.init();
                }, 0);
            },
            setHeight: function (ob, fade) {
                var obj = null,
                    $this = this;
                if (settings.loop) {
                    obj = ob.children('.lslide ').first();
                } else {
                    obj = ob.children().first();
                }
                var setCss = function () {
                    var tH = obj.outerHeight(),
                        tP = 0,
                        tHT = tH;
                    if (fade) {
                        tH = 0;
                        tP = ((tHT) * 100) / elSize;
                    }
                    ob.css({
                        'height': tH + 'px',
                        'padding-bottom': tP + '%'
                    });
                };
                setCss();
                if (obj.find('img').length) {
                    if ( obj.find('img')[0].complete) {
                        setCss();
                        if (!interval) {
                            $this.auto();
                        }   
                    }else{
                        obj.find('img').on('load', function () {
                            setTimeout(function () {
                                setCss();
                                if (!interval) {
                                    $this.auto();
                                }
                            }, 100);
                        });
                    }
                }else{
                    if (!interval) {
                        $this.auto();
                    }
                }
            },
            active: function (ob, t) {
                if (this.doCss() && settings.mode === 'fade') {
                    $slide.addClass('on');
                }
                var sc = 0;
                if (scene * settings.slideMove < length) {
                    ob.removeClass('active');
                    if (!this.doCss() && settings.mode === 'fade' && t === false) {
                        ob.fadeOut(settings.speed);
                    }
                    if (t === true) {
                        sc = scene;
                    } else {
                        sc = scene * settings.slideMove;
                    }
                    //t === true ? sc = scene : sc = scene * settings.slideMove;
                    var l, nl;
                    if (t === true) {
                        l = ob.length;
                        nl = l - 1;
                        if (sc + 1 >= l) {
                            sc = nl;
                        }
                    }
                    if (settings.loop === true && settings.mode === 'slide') {
                        //t === true ? sc = scene - $el.find('.clone.left').length : sc = scene * settings.slideMove;
                        if (t === true) {
                            sc = scene - $el.find('.clone.left').length;
                        } else {
                            sc = scene * settings.slideMove;
                        }
                        if (t === true) {
                            l = ob.length;
                            nl = l - 1;
                            if (sc + 1 === l) {
                                sc = nl;
                            } else if (sc + 1 > l) {
                                sc = 0;
                            }
                        }
                    }

                    if (!this.doCss() && settings.mode === 'fade' && t === false) {
                        ob.eq(sc).fadeIn(settings.speed);
                    }
                    ob.eq(sc).addClass('active');
                } else {
                    ob.removeClass('active');
                    ob.eq(ob.length - 1).addClass('active');
                    if (!this.doCss() && settings.mode === 'fade' && t === false) {
                        ob.fadeOut(settings.speed);
                        ob.eq(sc).fadeIn(settings.speed);
                    }
                }
            },
            move: function (ob, v) {
                if (settings.rtl === true) {
                    v = -v;
                }
                if (this.doCss()) {
                    if (settings.vertical === true) {
                        ob.css({
                            'transform': 'translate3d(0px, ' + (-v) + 'px, 0px)',
                            '-webkit-transform': 'translate3d(0px, ' + (-v) + 'px, 0px)'
                        });
                    } else {
                        ob.css({
                            'transform': 'translate3d(' + (-v) + 'px, 0px, 0px)',
                            '-webkit-transform': 'translate3d(' + (-v) + 'px, 0px, 0px)',
                        });
                    }
                } else {
                    if (settings.vertical === true) {
                        ob.css('position', 'relative').animate({
                            top: -v + 'px'
                        }, settings.speed, settings.easing);
                    } else {
                        ob.css('position', 'relative').animate({
                            left: -v + 'px'
                        }, settings.speed, settings.easing);
                    }
                }
                var $thumb = $slide.parent().find('.lSPager').find('li');
                this.active($thumb, true);
            },
            fade: function () {
                this.active($children, false);
                var $thumb = $slide.parent().find('.lSPager').find('li');
                this.active($thumb, true);
            },
            slide: function () {
                var $this = this;
                refresh.calSlide = function () {
                    if (w > elSize) {
                        slideValue = $this.slideValue();
                        $this.active($children, false);
                        if ((slideValue) > w - elSize - settings.slideMargin) {
                            slideValue = w - elSize - settings.slideMargin;
                        } else if (slideValue < 0) {
                            slideValue = 0;
                        }
                        $this.move($el, slideValue);
                        if (settings.loop === true && settings.mode === 'slide') {
                            if (scene >= (length - ($el.find('.clone.left').length / settings.slideMove))) {
                                $this.resetSlide($el.find('.clone.left').length);
                            }
                            if (scene === 0) {
                                $this.resetSlide($slide.find('.lslide').length);
                            }
                        }
                    }
                };
                refresh.calSlide();
            },
            resetSlide: function (s) {
                var $this = this;
                $slide.find('.lSAction a').addClass('disabled');
                setTimeout(function () {
                    scene = s;
                    $slide.css('transition-duration', '0ms');
                    slideValue = $this.slideValue();
                    $this.active($children, false);
                    plugin.move($el, slideValue);
                    setTimeout(function () {
                        $slide.css('transition-duration', settings.speed + 'ms');
                        $slide.find('.lSAction a').removeClass('disabled');
                    }, 50);
                }, settings.speed + 100);
            },
            slideValue: function () {
                var _sV = 0;
                if (settings.autoWidth === false) {
                    _sV = scene * ((slideWidth + settings.slideMargin) * settings.slideMove);
                } else {
                    _sV = 0;
                    for (var i = 0; i < scene; i++) {
                        _sV += (parseInt($children.eq(i).width()) + settings.slideMargin);
                    }
                }
                return _sV;
            },
            slideThumb: function () {
                var position;
                switch (settings.currentPagerPosition) {
                case 'left':
                    position = 0;
                    break;
                case 'middle':
                    position = (elSize / 2) - (thumbWidth / 2);
                    break;
                case 'right':
                    position = elSize - thumbWidth;
                }
                var sc = scene - $el.find('.clone.left').length;
                var $pager = $slide.parent().find('.lSPager');
                if (settings.mode === 'slide' && settings.loop === true) {
                    if (sc >= $pager.children().length) {
                        sc = 0;
                    } else if (sc < 0) {
                        sc = $pager.children().length;
                    }
                }
                var thumbSlide = sc * ((thumbWidth + settings.thumbMargin)) - (position);
                if ((thumbSlide + elSize) > pagerWidth) {
                    thumbSlide = pagerWidth - elSize - settings.thumbMargin;
                }
                if (thumbSlide < 0) {
                    thumbSlide = 0;
                }
                this.move($pager, thumbSlide);
            },
            auto: function () {
                if (settings.auto) {
                    clearInterval(interval);
                    interval = setInterval(function () {
                        $el.goToNextSlide();
                    }, settings.pause);
                }
            },
            pauseOnHover: function(){
                var $this = this;
                if (settings.auto && settings.pauseOnHover) {
                    $slide.on('mouseenter', function(){
                        $(this).addClass('ls-hover');
                        $el.pause();
                        settings.auto = true;
                    });
                    $slide.on('mouseleave',function(){
                        $(this).removeClass('ls-hover');
                        if (!$slide.find('.lightSlider').hasClass('lsGrabbing')) {
                            $this.auto();
                        }
                    });
                }
            },
            touchMove: function (endCoords, startCoords) {
                $slide.css('transition-duration', '0ms');
                if (settings.mode === 'slide') {
                    var distance = endCoords - startCoords;
                    var swipeVal = slideValue - distance;
                    if ((swipeVal) >= w - elSize - settings.slideMargin) {
                        if (settings.freeMove === false) {
                            swipeVal = w - elSize - settings.slideMargin;
                        } else {
                            var swipeValT = w - elSize - settings.slideMargin;
                            swipeVal = swipeValT + ((swipeVal - swipeValT) / 5);

                        }
                    } else if (swipeVal < 0) {
                        if (settings.freeMove === false) {
                            swipeVal = 0;
                        } else {
                            swipeVal = swipeVal / 5;
                        }
                    }
                    this.move($el, swipeVal);
                }
            },

            touchEnd: function (distance) {
                $slide.css('transition-duration', settings.speed + 'ms');
                if (settings.mode === 'slide') {
                    var mxVal = false;
                    var _next = true;
                    slideValue = slideValue - distance;
                    if ((slideValue) > w - elSize - settings.slideMargin) {
                        slideValue = w - elSize - settings.slideMargin;
                        if (settings.autoWidth === false) {
                            mxVal = true;
                        }
                    } else if (slideValue < 0) {
                        slideValue = 0;
                    }
                    var gC = function (next) {
                        var ad = 0;
                        if (!mxVal) {
                            if (next) {
                                ad = 1;
                            }
                        }
                        if (!settings.autoWidth) {
                            var num = slideValue / ((slideWidth + settings.slideMargin) * settings.slideMove);
                            scene = parseInt(num) + ad;
                            if (slideValue >= (w - elSize - settings.slideMargin)) {
                                if (num % 1 !== 0) {
                                    scene++;
                                }
                            }
                        } else {
                            var tW = 0;
                            for (var i = 0; i < $children.length; i++) {
                                tW += (parseInt($children.eq(i).width()) + settings.slideMargin);
                                scene = i + ad;
                                if (tW >= slideValue) {
                                    break;
                                }
                            }
                        }
                    };
                    if (distance >= settings.swipeThreshold) {
                        gC(false);
                        _next = false;
                    } else if (distance <= -settings.swipeThreshold) {
                        gC(true);
                        _next = false;
                    }
                    $el.mode(_next);
                    this.slideThumb();
                } else {
                    if (distance >= settings.swipeThreshold) {
                        $el.goToPrevSlide();
                    } else if (distance <= -settings.swipeThreshold) {
                        $el.goToNextSlide();
                    }
                }
            },



            enableDrag: function () {
                var $this = this;
                if (!isTouch) {
                    var startCoords = 0,
                        endCoords = 0,
                        isDraging = false;
                    $slide.find('.lightSlider').addClass('lsGrab');
                    $slide.on('mousedown', function (e) {
                        if (w < elSize) {
                            if (w !== 0) {
                                return false;
                            }
                        }
                        if ($(e.target).attr('class') !== ('lSPrev') && $(e.target).attr('class') !== ('lSNext')) {
                            startCoords = (settings.vertical === true) ? e.pageY : e.pageX;
                            isDraging = true;
                            if (e.preventDefault) {
                                e.preventDefault();
                            } else {
                                e.returnValue = false;
                            }
                            // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
                            $slide.scrollLeft += 1;
                            $slide.scrollLeft -= 1;
                            // *
                            $slide.find('.lightSlider').removeClass('lsGrab').addClass('lsGrabbing');
                            clearInterval(interval);
                        }
                    });
                    $(window).on('mousemove', function (e) {
                        if (isDraging) {
                            endCoords = (settings.vertical === true) ? e.pageY : e.pageX;
                            $this.touchMove(endCoords, startCoords);
                        }
                    });
                    $(window).on('mouseup', function (e) {
                        if (isDraging) {
                            $slide.find('.lightSlider').removeClass('lsGrabbing').addClass('lsGrab');
                            isDraging = false;
                            endCoords = (settings.vertical === true) ? e.pageY : e.pageX;
                            var distance = endCoords - startCoords;
                            if (Math.abs(distance) >= settings.swipeThreshold) {
                                $(window).on('click.ls', function (e) {
                                    if (e.preventDefault) {
                                        e.preventDefault();
                                    } else {
                                        e.returnValue = false;
                                    }
                                    e.stopImmediatePropagation();
                                    e.stopPropagation();
                                    $(window).off('click.ls');
                                });
                            }

                            $this.touchEnd(distance);

                        }
                    });
                }
            },




            enableTouch: function () {
                var $this = this;
                if (isTouch) {
                    var startCoords = {},
                        endCoords = {};
                    $slide.on('touchstart', function (e) {
                        endCoords = e.originalEvent.targetTouches[0];
                        startCoords.pageX = e.originalEvent.targetTouches[0].pageX;
                        startCoords.pageY = e.originalEvent.targetTouches[0].pageY;
                        clearInterval(interval);
                    });
                    $slide.on('touchmove', function (e) {
                        if (w < elSize) {
                            if (w !== 0) {
                                return false;
                            }
                        }
                        var orig = e.originalEvent;
                        endCoords = orig.targetTouches[0];
                        var xMovement = Math.abs(endCoords.pageX - startCoords.pageX);
                        var yMovement = Math.abs(endCoords.pageY - startCoords.pageY);
                        if (settings.vertical === true) {
                            if ((yMovement * 3) > xMovement) {
                                e.preventDefault();
                            }
                            $this.touchMove(endCoords.pageY, startCoords.pageY);
                        } else {
                            if ((xMovement * 3) > yMovement) {
                                e.preventDefault();
                            }
                            $this.touchMove(endCoords.pageX, startCoords.pageX);
                        }

                    });
                    $slide.on('touchend', function () {
                        if (w < elSize) {
                            if (w !== 0) {
                                return false;
                            }
                        }
                        var distance;
                        if (settings.vertical === true) {
                            distance = endCoords.pageY - startCoords.pageY;
                        } else {
                            distance = endCoords.pageX - startCoords.pageX;
                        }
                        $this.touchEnd(distance);
                    });
                }
            },
            build: function () {
                var $this = this;
                $this.initialStyle();
                if (this.doCss()) {

                    if (settings.enableTouch === true) {
                        $this.enableTouch();
                    }
                    if (settings.enableDrag === true) {
                        $this.enableDrag();
                    }
                }

                $(window).on('focus', function(){
                    $this.auto();
                });
                
                $(window).on('blur', function(){
                    clearInterval(interval);
                });

                $this.pager();
                $this.pauseOnHover();
                $this.controls();
                $this.keyPress();
            }
        };
        plugin.build();
        refresh.init = function () {
            refresh.chbreakpoint();
            if (settings.vertical === true) {
                if (settings.item > 1) {
                    elSize = settings.verticalHeight;
                } else {
                    elSize = $children.outerHeight();
                }
                $slide.css('height', elSize + 'px');
            } else {
                elSize = $slide.outerWidth();
            }
            if (settings.loop === true && settings.mode === 'slide') {
                refresh.clone();
            }
            refresh.calL();
            if (settings.mode === 'slide') {
                $el.removeClass('lSSlide');
            }
            if (settings.mode === 'slide') {
                refresh.calSW();
                refresh.sSW();
            }
            setTimeout(function () {
                if (settings.mode === 'slide') {
                    $el.addClass('lSSlide');
                }
            }, 1000);
            if (settings.pager) {
                refresh.createPager();
            }
            if (settings.adaptiveHeight === true && settings.vertical === false) {
                $el.css('height', $children.eq(scene).outerHeight(true));
            }
            if (settings.adaptiveHeight === false) {
                if (settings.mode === 'slide') {
                    if (settings.vertical === false) {
                        plugin.setHeight($el, false);
                    }else{
                        plugin.auto();
                    }
                } else {
                    plugin.setHeight($el, true);
                }
            }
            if (settings.gallery === true) {
                plugin.slideThumb();
            }
            if (settings.mode === 'slide') {
                plugin.slide();
            }
            if (settings.autoWidth === false) {
                if ($children.length <= settings.item) {
                    $slide.find('.lSAction').hide();
                } else {
                    $slide.find('.lSAction').show();
                }
            } else {
                if ((refresh.calWidth(false) < elSize) && (w !== 0)) {
                    $slide.find('.lSAction').hide();
                } else {
                    $slide.find('.lSAction').show();
                }
            }
        };
        $el.goToPrevSlide = function () {
            if (scene > 0) {
                settings.onBeforePrevSlide.call(this, $el, scene);
                scene--;
                $el.mode(false);
                if (settings.gallery === true) {
                    plugin.slideThumb();
                }
            } else {
                if (settings.loop === true) {
                    settings.onBeforePrevSlide.call(this, $el, scene);
                    if (settings.mode === 'fade') {
                        var l = (length - 1);
                        scene = parseInt(l / settings.slideMove);
                    }
                    $el.mode(false);
                    if (settings.gallery === true) {
                        plugin.slideThumb();
                    }
                } else if (settings.slideEndAnimation === true) {
                    $el.addClass('leftEnd');
                    setTimeout(function () {
                        $el.removeClass('leftEnd');
                    }, 400);
                }
            }
        };
        $el.goToNextSlide = function () {
            var nextI = true;
            if (settings.mode === 'slide') {
                var _slideValue = plugin.slideValue();
                nextI = _slideValue < w - elSize - settings.slideMargin;
            }
            if (((scene * settings.slideMove) < length - settings.slideMove) && nextI) {
                settings.onBeforeNextSlide.call(this, $el, scene);
                scene++;
                $el.mode(false);
                if (settings.gallery === true) {
                    plugin.slideThumb();
                }
            } else {
                if (settings.loop === true) {
                    settings.onBeforeNextSlide.call(this, $el, scene);
                    scene = 0;
                    $el.mode(false);
                    if (settings.gallery === true) {
                        plugin.slideThumb();
                    }
                } else if (settings.slideEndAnimation === true) {
                    $el.addClass('rightEnd');
                    setTimeout(function () {
                        $el.removeClass('rightEnd');
                    }, 400);
                }
            }
        };
        $el.mode = function (_touch) {
            if (settings.adaptiveHeight === true && settings.vertical === false) {
                $el.css('height', $children.eq(scene).outerHeight(true));
            }
            if (on === false) {
                if (settings.mode === 'slide') {
                    if (plugin.doCss()) {
                        $el.addClass('lSSlide');
                        if (settings.speed !== '') {
                            $slide.css('transition-duration', settings.speed + 'ms');
                        }
                        if (settings.cssEasing !== '') {
                            $slide.css('transition-timing-function', settings.cssEasing);
                        }
                    }
                } else {
                    if (plugin.doCss()) {
                        if (settings.speed !== '') {
                            $el.css('transition-duration', settings.speed + 'ms');
                        }
                        if (settings.cssEasing !== '') {
                            $el.css('transition-timing-function', settings.cssEasing);
                        }
                    }
                }
            }
            if (!_touch) {
                settings.onBeforeSlide.call(this, $el, scene);
            }
            if (settings.mode === 'slide') {
                plugin.slide();
            } else {
                plugin.fade();
            }
            if (!$slide.hasClass('ls-hover')) {
                plugin.auto();
            }
            setTimeout(function () {
                if (!_touch) {
                    settings.onAfterSlide.call(this, $el, scene);
                }
            }, settings.speed);
            on = true;
        };
        $el.play = function () {
            $el.goToNextSlide();
            settings.auto = true;
            plugin.auto();
        };
        $el.pause = function () {
            settings.auto = false;
            clearInterval(interval);
        };
        $el.refresh = function () {
            refresh.init();
        };
        $el.getCurrentSlideCount = function () {
            var sc = scene;
            if (settings.loop) {
                var ln = $slide.find('.lslide').length,
                    cl = $el.find('.clone.left').length;
                if (scene <= cl - 1) {
                    sc = ln + (scene - cl);
                } else if (scene >= (ln + cl)) {
                    sc = scene - ln - cl;
                } else {
                    sc = scene - cl;
                }
            }
            return sc + 1;
        }; 
        $el.getTotalSlideCount = function () {
            return $slide.find('.lslide').length;
        };
        $el.goToSlide = function (s) {
            if (settings.loop) {
                scene = (s + $el.find('.clone.left').length - 1);
            } else {
                scene = s;
            }
            $el.mode(false);
            if (settings.gallery === true) {
                plugin.slideThumb();
            }
        };
        $el.destroy = function () {
            if ($el.lightSlider) {
                $el.goToPrevSlide = function(){};
                $el.goToNextSlide = function(){};
                $el.mode = function(){};
                $el.play = function(){};
                $el.pause = function(){};
                $el.refresh = function(){};
                $el.getCurrentSlideCount = function(){};
                $el.getTotalSlideCount = function(){};
                $el.goToSlide = function(){}; 
                $el.lightSlider = null;
                refresh = {
                    init : function(){}
                };
                $el.parent().parent().find('.lSAction, .lSPager').remove();
                $el.removeClass('lightSlider lSFade lSSlide lsGrab lsGrabbing leftEnd right').removeAttr('style').unwrap().unwrap();
                $el.children().removeAttr('style');
                $children.removeClass('lslide active');
                $el.find('.clone').remove();
                $children = null;
                interval = null;
                on = false;
                scene = 0;
            }

        };
        setTimeout(function () {
            settings.onSliderLoad.call(this, $el);
        }, 10);
        $(window).on('resize orientationchange', function (e) {
            setTimeout(function () {
                if (e.preventDefault) {
                    e.preventDefault();
                } else {
                    e.returnValue = false;
                }
                refresh.init();
            }, 200);
        });
        return this;
    };
}(jQuery));;
