coreFramework.directive('cfBrowser', function (DataService) {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            contentType: '@',
            itemLink: '@',
            fileOver: '=',
            search: '=',
            linkable: '=?'
        },
        template:   '<div ng-class="{ \'is-contentLoading\': source.isLoading }">' +
                        '<cf-finder ng-if="finder" data-source="source" ng-hide="uploader && fileOver" advanced="{{ advanced }}"></cf-finder>' +
                        '<cf-list ng-if="list" data-source="source" linkable="linkable" item-link="{{itemLink}}" ng-hide="uploader && fileOver" default-variation="{{ defaultVariation }}"></cf-list>' +
                        '<cf-pager ng-if="pager" data-source="source" ng-hide="uploader && fileOver" url-params="urlParams"></cf-pager>' +
                        '<div ng-show="uploader && fileOver">' +
                            '<cf-uploader ng-if="uploader" data-source="source"></cf-uploader>' +
                        '</div>' +
                    '</div>',
        controller: ['$scope', '$attrs', '$location', '$timeout', function ($scope, $attrs, $location, $timeout) {

            $scope.finder = angular.isDefined($attrs.finder) ? $attrs.finder : false;
            $scope.list = angular.isDefined($attrs.list) ? $attrs.list : true;
            $scope.pager = angular.isDefined($attrs.pager) ? $attrs.pager : true;
            $scope.uploader = angular.isDefined($attrs.uploader) ? $attrs.uploader : false;
            $scope.advanced = angular.isDefined($attrs.advancedSearch) ? $attrs.advancedSearch : '';

            $scope.linkable = angular.isDefined($scope.linkable) ? !!$scope.linkable : true;

            $scope.urlParams = angular.isDefined($attrs.urlParams) ? $attrs.urlParams : false;

            $scope.defaultVariation = angular.isDefined($attrs.defaultVariation) ? $attrs.defaultVariation : null;


            if ($attrs.source && $attrs.source.indexOf('/') == -1) {
                $scope.source = $scope.$parent.$eval($attrs.source);
            }

            if (angular.isUndefined($scope.source)) {
                $scope.source = new DataService($attrs.source, $scope.contentType);
            }

            if (angular.isDefined($attrs.limit)) {
                $scope.source.setOption('limit', $attrs.limit);
            }
            if (angular.isDefined($attrs.order)) {
                $scope.source.setOption('order', $attrs.order);
            }
            if (angular.isDefined($attrs.origin)) {
                $scope.source.origin = $scope.$parent.$eval($attrs.origin);
            }
            if (angular.isDefined($scope.search)) {
                $scope.source.setOption('query', $scope.search);
            }

            $scope.$watch('search', function (value, oldVal) {
                if (value != oldVal) {
                    if ($scope.urlParams) {
                        $location.search('query', value ? value : null);
                    } else {
                        $scope.source.setOption('query', value);
                        $scope.source.setOption('offset', 0);
                        $scope.source.get();
                    }
                }
            });

            if ($scope.urlParams) {
                var urlParams = $location.search();
                if (angular.isDefined(urlParams.page)) {
                    $scope.source.setOption('offset', Math.max(0, parseInt(urlParams.page, 10) - 1) * $scope.source.getOption('limit'));
                }
                if (angular.isDefined(urlParams.query)) {
                    $scope.source.setOption('query', urlParams.query);
                    $scope.search = urlParams.query;
                } else {
                    if ($scope.search) {
                        $location.search('query', $scope.search);
                    }
                }
                $scope.$on('$locationChangeSuccess', function () {
                    var urlParams = $location.search();
                    var reload = false;
                    var offset;
                    if (angular.isDefined(urlParams.page)) {
                        offset = Math.max(0, parseInt(urlParams.page, 10) - 1) * $scope.source.getOption('limit');
                    } else {
                        offset = 0;
                    }
                    if (offset != $scope.source.getOption('offset')) {
                        $scope.source.setOption('offset', offset);
                        reload = true;
                    }
                    if (urlParams.query != $scope.source.getOption('query') && !(angular.isUndefined(urlParams.query) && $scope.source.getOption('query') == "")) {
                        $scope.source.setOption('query', urlParams.query);
                        $scope.search = urlParams.query;
                        if (offset) {
                            $location.search('page', null);
                            return;
                        }
                        reload = true;
                    }
                    if (reload) {
                        $scope.source.get();
                    }
                });
            }

            angular.forEach($scope.$eval($attrs.params), function(value, key) {
                $scope.source.setOption(key, value);
            });

            $scope.source.get();

        }]
    };
});
coreFramework.directive('cfFinder', function ($compile, AssignmentService, cfScopeCollection) {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            source: '='
        },
        template:   function (element, attrs) {
            return '<div>' +
                        '<form ng-submit="submit()" class="g g-12 Panel-search form-inline" role="form">' +
                            '<div class="g-4 pl-0 FormElement" ng-if="showOrigin()">' +
                                '<select class="Input Input--small" placeholder="Enter term(s)" ng-model="queryParts.origin" ng-change="submit()" ng-options="o.value as o.label for o in relatedParts"></select>' +
                            '</div>' +
                            '<div class="g-8 pr-0"><div class="FormElement FormElement--group finder-search-field">' +
                                '<input type="text" ng-model="queryParts.query" ng-change="autoSubmit()" class="Input Input--small" />' +
                                '<span class="ButtonGroup">' +
                                    '<button type="submit" class="Button Button--simple"><i class="fa fa-search"></i></button>' +
                                '</span>' +
                            '</div></div>' +
                        '</form>' +
                    '</div>'
        },
        link: function (scope, element, attrs) {
            var el = $(element).find('.finder-search-field');
            attrs.$observe('advanced', function (value) {
                el.find('input, div').remove();
                $(element).find('[cf-search-engine-filters-name]').remove();
                if (value) {
                    el.html('<div cf-search-engine="' + value + '"></div>');
                    $(element).append('<div class="g g-3 g-full" cf-search-engine-filters-name="' + value + '" ng-include="$root.advancedSearch.getModule(\'' + value + '\').form"></div>');
                    scope.searchScope = cfScopeCollection.get(value);
                } else {
                    el.html('<input type="text" ng-model="queryParts.query" ng-change="autoSubmit()" class="Input Input--small" />');
                    scope.searchScope = null;
                }
                $compile(element.contents())(scope);
            });
        },
        controller: ['$scope', '$timeout', function ($scope, $timeout) {

            $scope.showOrigin = function() {
                return $scope.source.origin && $scope.source.origin != AssignmentService.STATIC;
            }

            $scope.relatedParts = [
                { label: 'All ' + $scope.source.type + 's', value: '' },
                { label: 'Related', value: $scope.source.origin },
                { label: 'Inserted', value: AssignmentService.STATE }
            ];
            $scope.queryParts = {
                query: null,
                origin: $scope.source.origin || ''
            };

            $scope.$watch('source.origin', function() {
                //$scope.queryParts.origin = $scope.source.origin || '';
            });
            $scope.$watch(function() { return $scope.source.getOption('origin'); }, function() {
                $scope.queryParts.origin = $scope.source.getOption('origin') || '';
            });
            $scope.$watch('source.query', function() {
                $scope.queryParts.query = $scope.source.query || '';
            });
            $scope.$watch('searchScope.searchEngineTemp', function(value, oldValue) {
                if (value != oldValue) {
                    $scope.queryParts.query = value;
                    $scope.submit();
                }
            });
            $scope.$watch('source.type', function() {
                $scope.relatedParts[0].label = 'All ' + $scope.source.type + 's';
            });

            $scope.autoSubmit = function() {
                $timeout.cancel($scope.submitTimeout);
                $scope.submitTimeout = $timeout(function() {
                    if ($scope.queryParts.query == '' || $scope.queryParts.query.length >= 2) {
                        $scope.submit();
                    }
                }, 1000);
            };

            $scope.submit = function() {

                $scope.source.setOption('query', $scope.queryParts.query);
                $scope.source.setOption('origin', $scope.queryParts.origin);
                $scope.source.setOption('offset', 0);
                $scope.source.get();

            }

        }]
    }
});
coreFramework.directive('cfList', function ($location, AssignmentService) {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            source: '=',
            //highlight: '=',
            linkable: '=',
            itemLink: '@',
            defaultVariation: '@'
        },
        template:   '<div class="cf-list cf-list-type-{{source.type}}">' +
                        '<div draggable="{{ itemLink ? false : true }}" class="cf-list-item" ng-repeat="item in source.data track by $index">' +
                            '<a ng-if="item.id" ng-href="{{ itemUrl(item.id) }}" ng-click="select(item)" style="transition: none; -moz-transition: none; -webkit-transition: none;">' +
                                '<cf-list-item></cf-list-item>' +
                            '</a>' +
                            '<a ng-if="!item.id" ng-click="select(item)" style="transition: none; -moz-transition: none; -webkit-transition: none;">' +
                                '<cf-list-item></cf-list-item>' +
                            '</a>' +
                        '</div>' +
                        '<div class="ContentPreloader">' +
                            '<div class="ContentPreloader-inner">' +
                                '<i class="ContentPreloader-circle ContentPreloader-circle--1"></i>' +
                                '<i class="ContentPreloader-circle ContentPreloader-circle--2"></i>' +
                                '<i class="ContentPreloader-circle ContentPreloader-circle--3"></i>' +
                            '</div>' +
                        '</div>' +
                    '</div>',
        controller: ['$scope', 'AssignmentMediator', function ($scope, AssignmentMediator) {
            $scope.$watch(function() {
                return AssignmentService.getList($scope.source.type);
            }, function(value) {
                $scope.highlight = value;
            }, true);

            $scope.itemUrl = function(id) {
                return $scope.linkable && $scope.itemLink ? $scope.itemLink + id + '/' : '';
            }

            $scope.select = function(item) {
                if ($scope.linkable && !$scope.itemLink) {
                    AssignmentMediator.send(item, $scope.source.type);
                }
            }

        }]
    }
});
coreFramework.directive('cfListItem', function ($compile, ItemTypes) {
    return {
        restrict: 'E',
        replace: true,
        scope: true,
        require: '^cfList',
        controller: ['$scope', function ($scope) {

            $scope.assignedTo = [];

            $scope.$watch('[highlight, item]', function() {
                if ($scope.item && $scope.item.id && $scope.highlight) {
                    $scope.elementClass = ($scope.highlight.map(function(item){ return item.id; }).indexOf($scope.item.id) == -1) ? '' : 'is-selected';
                    $scope.assignedTo = [];
                    angular.forEach($scope.highlight, function(item){
                        if ($scope.item.id == item.id)
                        $scope.assignedTo = item.assignedTo;
                    });
                }
            }, true);

        }],
        compile: function(element, attrs) {
            
            return function(scope, element, attrs) {

                element.parent().parent().on('dragstart', function (e) {
                    console.log('dragstart');
                    e = e.originalEvent;
                    e.dataTransfer.setData(scope.source.type, JSON.stringify(scope.item));
                    //return false;
                });

                var itemElement = ItemTypes.get(scope.source.type).directive;
                var template =  '<div class="cf-list-item" ng-class="elementClass" style="position: relative;">' +
                                    '<span class="ImageVariation">' +
                                        '<span ng-repeat="elem in assignedTo" class="ImageVariation-item">{{elem}}</span>' +
                                    '</span>' +
                                    '<' + itemElement + '></' + itemElement + '>' +
                                '</div>';

                element.html(template).show();
                $compile(element.contents())(scope);

            }

        }
    }
});
coreFramework.directive('cfPager', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            source: '=',
            urlParams: '='
        },
        template:   '<div ng-show="hasPages()">' +
                        '<div kendo-pager k-data-source="dataSource" k-button-count="5"></div>' +
                    '</div>',
        controller: ['$scope', 'Restangular', '$location', '$timeout', function ($scope, Restangular, $location, $timeout) {

            $scope.hasPages = function () {
                return ($scope.source && $scope.source.count && $scope.source.getOption('limit') && parseInt($scope.source.count, 10) > $scope.source.getOption('limit'));
            };

            $scope.dataSource = new kendo.data.DataSource({
                //data: $scope.source.data,
                transport: {
                    read : function (options) {

                        if (!$scope.source.getOption('offset')) {
                            $scope.source.setOption('offset', 0);
                        }
                        if ($scope.source.getOption('offset') == options.data.skip) {
                            options.success($scope.source.data);
                        } else {
                            if ($scope.urlParams) {
                                $timeout(function () {
                                    $location.search('page', options.data.skip ? 1 + Math.floor(options.data.skip / $scope.source.getOption('limit')) : null);
                                });
                            } else {
                                $scope.source.setOption('offset', options.data.skip);
                                $scope.source.get();
                            }
                            /*$scope.source.get().then(function() {
                                //options.success($scope.source.data);
                            });*/
                        }

                    }
                },
                schema: {
                    total: function (response) {
                        return parseInt($scope.source.count, 10);

                    }
                },
                pageSize: $scope.source.getOption('limit'),
                serverPaging: true,
                serverFiltering: true,
                serverSorting: true
            });

            $scope.$watch('source.data', function() {

                if ($scope.dataSource.pageSize() != $scope.source.getOption('limit')) {
                    $scope.dataSource.pageSize($scope.source.getOption('limit'));
                }
                if ($scope.source.data && $scope.source.data.length) {
                    var page = $scope.source.getOption('offset') && $scope.source.getOption('limit') ? Math.floor($scope.source.getOption('offset') / $scope.source.getOption('limit')) : 0;
                    $scope.dataSource.success($scope.source.data);
                    $scope.dataSource.page(page + 1);
                } else {
                    $scope.dataSource.success([]);
                }

            }, true);

        }]
    }
});
coreFramework.filter('trustedResource', ['$sce', function($sce) {
    return function(val) {
        return $sce.getTrustedResourceUrl(val);
    };
}]);

coreFramework.directive('cfUploader', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: true,
        template:   '<input type="file" kendo-upload k-async="async" k-on-success="onSuccess(kendoEvent)" k-on-progress="onProgress(kendoEvent)" k-on-error="onError(kendoEvent)" k-on-upload="onUpload(kendoEvent)" />',
        controller: ['$scope', '$attrs', 'Auth', 'Message', function ($scope, $attrs, Auth, Message) {

            if (angular.isUndefined($scope.source)) {
                $scope.source = $scope.$eval($attrs.source);
            }

            $scope.async = {
                saveUrl: $scope.source.api + ($scope.source.origin ? '?origin=' + $scope.source.origin : ''),
                saveField: $scope.source.type + 's',
                autoUpload: true
            };

            $scope.uploadingFiles = 0;

            var getBlobURL = (window.URL && URL.createObjectURL.bind(URL)) ||
                (window.webkitURL && webkitURL.createObjectURL.bind(webkitURL)) ||
                window.createObjectURL;
            var revokeBlobURL = (window.URL && URL.revokeObjectURL.bind(URL)) ||
                (window.webkitURL && webkitURL.revokeObjectURL.bind(webkitURL)) ||
                window.revokeObjectURL;

            $scope.onProgress = function (e) {

                var _temp = {
                    progress: 0
                };

                for (var i = 0; i < $scope.source.dummyData.length; i++) {
                    if ($scope.source.dummyData[i].name == e.files[0].name) {
                        // if ($scope.source.dummyData[i].progress > 0) {
                        //     continue;
                        // }
                        // _temp.item = $scope.source.dummyData[i];
                        // TweenMax.to(_temp, 4, { progress: (isNaN(e.percentComplete) ? 0 : e.percentComplete), onUpdate: function() {
                        //     $scope.$apply(function () {
                        //         _temp.item.progress = _temp.progress;
                        //     });
                        // }, onComplete: $scope.onComplete });
                        $scope.source.dummyData[i].progress = isNaN(e.percentComplete) ? 0 : e.percentComplete;
                        break;
                    }
                }


            };

            $scope.onSuccess = function (e) {

                Message.send('Uploaded!', 'success');
                $scope.source.setOption('offset', 0);
                $scope.source.get();

                // $scope.uploadingFiles--;

                // if ($attrs.setEvents && $scope.uploadingFiles == 0) {
                //     if ($scope.$parent[$attrs.setEvents] == 3) {
                //         $scope.$parent[$attrs.setEvents] = 1;
                //     } else if ($scope.$parent[$attrs.setEvents] == 2) {
                //         $scope.$parent[$attrs.setEvents] = 0;
                //     }
                // }

            };

            $scope.onError = function (e) {

                Message.send('Error!', 'error');

                for (var i = 0; i < $scope.source.dummyData.length; i++) {
                    if ($scope.source.dummyData[i].name == e.files[0].name) {
                        $scope.source.dummyData.splice(i, 1);
                        break;
                    }
                }

                // $scope.uploadingFiles--;

                // if ($attrs.setEvents && $scope.uploadingFiles == 0) {
                //     if ($scope.$parent[$attrs.setEvents] == 3) {
                //         $scope.$parent[$attrs.setEvents] = 1;
                //     } else if ($scope.$parent[$attrs.setEvents] == 2) {
                //         $scope.$parent[$attrs.setEvents] = 0;
                //     }
                // }

            };

            $scope.onUpload = function (e) {

                console.log(e);

                if (e.files[0].rawFile.type.substring(0,6) === 'image/') {
                    // var img = document.createElement('img');
                    //     img.src = getBlobURL(e.files[0].rawFile);
                    //     img.onload = function() {
                    //         e.files[0].snapshot = this.src;
                    //         revokeBlobURL(this.src);
                    //     }
                    e.files[0].snapshot = getBlobURL(e.files[0].rawFile);
                }

                $scope.source.dummyData.push(e.files[0]);

                // $scope.uploadingFiles++;

                // if ($attrs.setEvents) {
                //     $scope.$parent[$attrs.setEvents] = 2;
                // }
                //return;
                var xhr = e.XMLHttpRequest;

                if (xhr) {
                    xhr.addEventListener('readystatechange', function (e) {
                        if (xhr.readyState == 1) {
                            xhr.setRequestHeader('Authorization', 'Bearer ' + Auth.getToken());
                            xhr.setRequestHeader('Content-Language', $scope.$root.language);
                        }
                    });
                }

            };

        }]
    }
});
coreFramework.directive('cfDragFiles', function ($timeout) {
    return {
        restrict: 'A',
        scope: {
            cfDragFiles: '='
        },
        link: function (scope, element, attrs) {

            element.on('dragover', function (e) {
                
                if (e.originalEvent) e = e.originalEvent;
                if (e.preventDefault) e.preventDefault();

                var isFiles = (e.dataTransfer.types && e.dataTransfer.types.length && [].indexOf.call(e.dataTransfer.types, 'Files') >= 0);
                if (isFiles && scope.to) {
                    $timeout.cancel(scope.to);
                }
                scope.$apply(function () {
                    var status = scope.cfDragFiles > 1 ? 2 : 0;
                    scope.cfDragFiles = isFiles ? status + 1 : status;
                });
                scope.to = $timeout(function () {
                    if (scope.cfDragFiles == 1) {
                        scope.cfDragFiles = 0;
                    }
                }, 100);
                
                return false;
            });

            element.on('dragenter', function (e) {
                if (e.originalEvent) e = e.originalEvent;
                if (e.preventDefault) e.preventDefault();

                return false;
            });

            element.on('drop', function (e) {
                if (e.originalEvent) e = e.originalEvent;
                if (e.preventDefault) e.preventDefault();

                return false;
            });

        }
    };
});

coreFramework.directive('cfModuleSearch', function () {
    return {
        restrict: 'E',
        template:   '<form role="search" class="Search-form FormSearch">' +
                        '<div class="FormElement FormElement--group">' +
                            '<label class="u-isHidden">Search</label>' +
                            '<input type="text" ng-model="searchText" class="Input Input--small Search-term" placeholder="Enter term(s)" />' +
                            '<div class="ButtonGroup">' +
                                '<button type="submit" class="Button Button--simple js-showRwdSearch" ng-click="search()"><i class="fa fa-search"></i></button>' +
                            '</div>' +
                        '</div>' +
                    '</form>',
        scope: {
            data: '='
        },
        controller: ['$scope', '$rootScope', '$location', '$timeout', function ($scope, $rootScope, $location, $timeout) {

            $scope.$watch('data', function (value) {
                if (value && value != $scope.searchText) {
                    $scope.searchText = value;
                }
            });

            $scope.search = function () {
                $scope.data = $scope.searchText;
                var appPath = $location.path().split('/admin/')[1].replace(/\/$/, '').split('/');
                if (appPath.length && appPath[0] && appPath[1] != 'list') {
                    $location.path('/admin/' + appPath[0] + '/list/');
                }
            };

            $rootScope.$on('$routeChangeStart', function(a, b, c) {
                var appPath = $location.path().split('/admin/')[1].replace(/\/$/, '').split('/');
                if (appPath.length) {
                    if ($scope.module != appPath[0]) {
                        $scope.searchText = '';
                        $scope.data = '';
                    }
                    $scope.module = appPath[0];
                }
            });

        }]
    };
});

coreFramework.directive('cfFileUpload', function () {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: {
            data: '=ngModel',
            type: '@contentType',
            apiEndpoint: '@',
            apiParams: '@',
            isWorking: '='
        },
        template:   '<div class="cf-file-upload" ng-class="{ loading: isLoading, \'file-over\': dropClass }" flow-drag-enter="dropClass=true" flow-drag-leave="dropClass=false">' +
                        '<div class="cf-file-upload-drop" flow-init="flowOptions" flow-drop flow-file-success="flow(\'fileSuccess\', $flow, $file)" flow-file-progress="flow(\'fileProgress\', $flow, $file)" flow-files-submitted="flow(\'filesSubmitted\', $flow, $files)">' +
                            '<div ng-hide="isLoading || isProcessing" class="cf-file-upload-placeholder" ng-transclude></div>' +
                            '<div ng-show="isLoading" class="cf-file-upload-progress" style="width: {{ 100 * (($flow.files[0].progress()) || 0) }}%;"></div>' +
                            '<div ng-show="isLoading" class="cf-file-upload-placeholder"><i class="fa fa-cog fa-spin"></i> Uploading...</div>' +
                            '<div ng-show="isProcessing" class="cf-file-upload-placeholder"><i class="fa fa-cog fa-spin"></i> Processing...</div>' +
                            // '<div ng-show="item">' +
                            //     '<div class="cf-form-entity-item">' +
                            //         '<' + itemElement + ' class="" flow-img="$flow.files[0]"></' + itemElement + '>' +
                            //         '<div class="cf-form-entity-item-progress" ng-class="{ complete: $flow.files[0] ? $flow.files[0].progress() == 1 : false }" ng-if="$flow.files[0] && $flow.files[0].progress()" style="width: {{ 100 * ((1 - $flow.files[0].progress()) || 1) }}%;"></div>' +
                            //         '<div class="cf-form-entity-item-overlay">' +
                            //             '<div class="cf-form-entity-item-overlay-title">{{ item.title }}</div>' +
                            //             '<a ng-click="remove()" class="cf-form-entity-item-overlay-button">Remove</a>' +
                            //             '<a ng-if="image_url" ng-click="preview()" class="cf-form-entity-item-overlay-button">Preview</a>' +
                            //             '<span flow-btn flow-single-file class="cf-form-entity-item-overlay-button">Replace</span>' +
                            //             (showEditButton ? '<a href="/admin/{{apiEndpoint}}/edit/{{item.id}}/{{ imageVariation ? \'?variation=\' + imageVariation : \'\' }}" class="cf-form-entity-item-overlay-button">Edit</a>' : '') +
                            //         '</div>' +
                            //     '</div>' +
                            // '</div>' +
                            // '<div class="cf-form-entity-item" ng-show="!item">' +
                            //     '<span flow-btn flow-single-file class="Button">Add {{buttonLabel || "entity"}}</span>' +
                            //     '<span class="description">Drag from computer or <a ng-click="register()">panel on the right</a>!</span>' +
                            // '</div>' +
                        '</div>' +
                    '</div>',
        controller: ['$scope', 'Restangular', 'Auth', 'Message', '$attrs', '$timeout', function ($scope, Restangular, Auth, Message, $attrs, $timeout) {
            $scope.$watch('apiEndpoint', function (value) {
                $scope.$$childHead.$flow.opts.target = '/api/' + value + '/';
            });
            $scope.flowOptions = {
                target: '/api/' + $scope.apiEndpoint + '/',
                headers: {
                    'Authorization': 'Bearer ' + Auth.getToken()
                },
                fileParameterName: $scope.type + 's',
                withCredentials: true,
                testChunks: false,
                singleFile: true,
                progressCallbacksInterval: 10,
                chunkSize: 24 * 1024 * 1024
            };
            $scope.flow = function (eventType, flow, flowObj) {
                switch (eventType) {
                    case 'fileSuccess':
                        $scope.isLoading = false;
                        $scope.isProcessing = true;
                        var apiParams = angular.extend({}, $scope.$eval($scope.apiParams));
                        Restangular.oneUrl('item', flowObj.chunks[0].itemLocation).get(apiParams).then(function (response) {
                            $scope.isProcessing = false;
                            $scope.isWorking = false;
                            $scope.data = response.data.originalElement;
                            flow.cancel();
                        });
                        break;
                    case 'filesSubmitted':
                        // $scope.item = {};
                        $scope.isLoading = true;
                        $scope.isWorking = true;
                        flow.resume();
                        break;
                }
            };
        }],
        link: function (scope, element, attrs, ctrl) {

        }
    };
});

coreFramework.directive('cfFileUploadButton', function () {
    return {
        restrict: 'EA',
        replace: true,
        transclude: true,
        scope: false,
        template:   '<span flow-single-file class="Button Button--small Button--neutral">' +
                        '<span ng-transclude></span>' +
                    '</span>',
        controller: ['$scope', function ($scope) {
            asdasd = $scope;
        }],
        link: function (scope, element, attrs) {
            var isDirectory = attrs.hasOwnProperty('flowDirectory');
            var isSingleFile = attrs.hasOwnProperty('flowSingleFile');
            var inputAttrs = attrs.hasOwnProperty('flowAttrs') && scope.$eval(attrs.flowAttrs);
            element.parent().parent().scope().$flow.assignBrowse(element, isDirectory, isSingleFile, inputAttrs);
        }
    };
});


// advanced search

coreFramework.directive('cfSearchEngine', function ($rootScope, $location, $filter, $timeout, cfScopeCollection, cfLocationService, cfSearchEnginePersistService) {
    return {
        restrict: 'A',
        template:   '<div ng-show="showSearch" class="Search-form FormSearch">' +
                        '<div class="FormElement FormElement--group">' +
                            '<span class="u-isHidden" ng-hide="value == \'\'" ng-repeat="(key, value) in searchScope.searchEngineQuery.tokens" cf-change-segmented="searchScope.searchEngine.tokens[key] = \'\'; searchScope.searchEngineQuery = copyObject(searchScope.searchEngine);">' +
                                '{{ key }}: {{ value }}' +
                            '</span>' +
                            '<input class="Input Input--small Search-term" type="text" ng-focus="searchScope.showForm = true;" ng-model="searchScope.searchEngine.query" cf-change-segmented="searchScope.searchEngineQuery = copyObject(searchScope.searchEngine);" placeholder="Enter term(s)" />' +
                            '<div class="ButtonGroup"><span class="Button Button--simple js-showRwdSearch"><i class="fa fa-search"></i></span></div>' +
                            '<span class="Search-advanced" ng-if="0 && searchScope.searchEngineStructure && !searchScope.showForm" ng-click="searchScope.showForm = true;">Advanced search</span>' +
                            '<span class="Search-advanced" ng-if="searchScope.searchEngineStructure">' +
                                '<i class="fa fa-angle-down" ng-if="!searchScope.showForm" ng-click="searchScope.showForm = true;"></i>' +
                                '<i class="fa fa-angle-up" ng-if="searchScope.showForm" ng-click="searchScope.showForm = false;"></i>' +
                            '</span>' +
                        '</div>' +
                    '</div>',
        link: function (scope, element, attrs) {
            var scopeName = attrs.cfSearchEngine || 'query';
            scope.searchScope = cfScopeCollection.get(scopeName);
            if (!scope.searchScope.searchEngine) {
                scope.searchScope.searchEngine = angular.copy($filter('cfTokenizer')(null, scope.searchScope.searchEngineStructure));
            }
            if (scopeName == 'query') {
                cfLocationService.bindParam(scope.searchScope, 'searchEngineTemp', scopeName);
            }

            //cfSearchEnginePersistService.bindParam(scope.searchScope, 'searchEngineTemp', scopeName);
            scope.searchScope.$watch('searchEngineQuery', function (value, oldValue) {
                if (value != oldValue) {
                    var formated = $filter('cfTokenizer')(value ? value.query : null, scope.searchScope.searchEngineStructure);
                    if (formated && angular.isObject(formated)) {
                        formated.tokens = angular.extend((value ? value.tokens : null) || {}, formated.tokens || {});
                    }
                    if (scope.searchScope.searchEngineStructure) {
                        angular.forEach(scope.searchScope.searchEngineStructure, function (value, key) {
                            formated.tokens[key] = formated.tokens[key] || '';
                        });
                    }
                    scope.searchScope.searchEngine = angular.copy(formated);
                    scope.searchScope.searchEngineTemp = $filter('cfTokenizer')(formated, scope.searchScope.searchEngineStructure, true);
                }
            }, true);

            scope.searchScope.$watch('searchEngineTemp', function (value, oldValue) {
                if (value != oldValue) {
                    var formated = $filter('cfTokenizer')(value, scope.searchScope.searchEngineStructure);
                    if (scope.searchScope.searchEngineStructure) {
                        angular.forEach(scope.searchScope.searchEngineStructure, function (value, key) {
                            formated.tokens[key] = formated.tokens[key] || '';
                        });
                    }
                    scope.searchScope.searchEngineQuery = formated;
                    scope.searchScope.searchEngine = angular.copy(scope.searchScope.searchEngineQuery);
                }
            });

            scope.searchScope.$watch('searchEngineStructure', function (value, oldValue) {
                $timeout(function () {
                    scope.searchScope.searchEngineQuery = scope.searchScope.searchEngineQuery || {};
                    scope.searchScope.searchEngineQuery.change = Math.random();
                });
            });

            function hideForm (e) {
                $timeout(function () {
                    if (e.keyCode) {
                        if (e.keyCode == 27) {
                            scope.searchScope.showForm = false;
                        }
                    } else if ($(scope.searchScope.filterElement).find(':input:focus').length == 0) {
                        scope.searchScope.showForm = false;
                    }
                });
            };

            element.find('.Search-term').bind('mousedown', function (e) {
                e.stopPropagation();
            });

            scope.searchScope.$watch('showForm', function (value) {
                if (value) {
                    angular.element(document).bind('mousedown keydown', hideForm);
                } else {
                    angular.element(document).unbind('mousedown keydown', hideForm);
                }
            });

            function checkRoute () {
                var appPath = $location.path().split('/admin/')[1].replace(/\/$/, '').split('/');
                if (appPath.length) {
                    scope.showSearch = true;
                    if (scopeName == 'query') {
                        if (appPath[0] == 'sitemap') {
                            scope.showSearch = false;
                        }
                        if (appPath[0] == 'productchooser') {
                            scope.showSearch = false;
                        }
                        // if (appPath.length > 1 && angular.lowercase(appPath[1]) != 'list') {
                        //     scope.showSearch = false;
                        // }
                    }
                    
                    if (scope.module != appPath[0]) {
                        $timeout(function () {
                            scope.searchScope.showForm = false;
                            scope.searchScope.searchEngineStructure = null;
                        });
                    }

                    scope.module = appPath[0];
                }
            };

            $rootScope.$on('$routeChangeStart', checkRoute);
            // $rootScope.$on('$locationChangeSuccess', function () {
            //     if (scopeName == 'query' && Object.keys($location.search()).length) {
            //         $timeout(function () {
            //             console.log('$locationChangeSuccess', $location.search());
            //             scope.searchObject = $location.search();
            //         });
            //     }
            // });
            // $rootScope.$on('$routeChangeSuccess', function (a,b,c) {
            //     console.log(a,b,c);
            //     if (scopeName == 'query' && scope.searchObject) {
            //         $timeout(function () {
            //             console.log('$routeChangeSuccess', scope.searchObject);
            //             $location.search(scope.searchObject);
            //         });
            //     }
            // });

            checkRoute();

        }
    };
});

coreFramework.directive('aQQQ', function ($rootScope, $timeout, $location) {

    $rootScope.$on('$locationChangeSuccess', function () {
        $timeout(function () {
            $rootScope.searchObject = $location.search();
        });
    });

    return {
        restrict: 'E',
        link: function (scope, element, attrs) {

            $rootScope.$watch('searchObject', function (value) {
                console.log(attrs['href'].split('/'), $location.path().split('/'));
                if (attrs['href'] && value && attrs['href'].split('/')[2] == $location.path().split('/')[2]) {
                    attrs.$set('href', attrs['href'].split('?')[0] + (value ? '?' + $.param(value) : ''));
                }
            }, true);

        }
    };
});

coreFramework.directive('cfSearchEngineFilters', function ($timeout, cfScopeCollection) {
    return {
        restrict: 'A',
        replace: true,
        transclude: true,
        scope: {
            searchScopeName: '@cfSearchEngineFilters'
        },
        template:   '<div class="Filters g-wrapper cfSearchFilters" ng-show="searchScope.showForm">' +
                        '<a class="Filters-close" ng-click="searchScope.showForm = false;">Close <span class="fa fa-times"></span></a>' +
                        '<a class="Filters-close" style="right: 100px;" ng-click="searchScope.searchEngineQuery = {}; data = copyObject(searchScope.searchEngine.tokens);">Clear <span class="fa fa-eraser"></span></a>' +
                        '<div class="Filters-inner g-container" ng-form="form" cf-form-structure="formStructure" cf-change-segmented="searchScope.searchEngineQuery = copyObject(searchScope.searchEngine);"></div>' +
                    '</div>',
        link: function(scope, element, attrs, ctrl) {
            
            scope.searchScope = cfScopeCollection.get(element.parent().attr('cf-search-engine-filters-name') || scope.searchScopeName || 'query');
            scope.searchScope.filterElement = element;
            scope.$watch('formStructure', function (value) {
                $timeout(function () {
                    scope.searchScope.searchEngineStructure = value;
                });
            });

            var el = element.find('.Filters-inner');
            ctrl.transclude(scope, function(clone) {
                el.empty();
                el.append(clone);
            });

            element.bind('mousedown', function (e) {
                e.stopPropagation();
            });

            scope.searchScope.$watch('searchEngine.tokens', function (value) {
                if (value) {
                    scope.data = angular.copy(value);
                }
            }, true);
            // scope.$watch('data', function (value) {
            //     if (value) {
            //         scope.searchScope.searchEngine.tokens = angular.copy(value);
            //     }
            // }, true);
            scope.search = function (data) {
                scope.searchScope.searchEngine.tokens = angular.copy(data);
                scope.searchScope.showForm = false;
            };

        },
        controller: ['$transclude', function ($transclude) {

            this.transclude = $transclude;
        }]
    };
});

coreFramework.animation('.cfSearchFilters', function () {
    var duration = .2;
    var ease = Quad;

    return {
        beforeAddClass: function(element, className, done) {

            if (className == 'ng-hide') {

                TweenMax.killTweensOf(element);
                TweenMax.to(element, duration * .5, { opacity: 0, height: 0, y: -50, onComplete: done, ease: ease.easeIn });

            } else {
                done();
            }

        },
        removeClass: function(element, className, done) {
            
            if (className == 'ng-hide') {
                TweenMax.killTweensOf(element);
                element.css({
                    overflow: 'hidden',
                    maxHeight: (parseInt(element.css('maxHeight')) || element[0].clientHeight) + 'px'
                });

                TweenMax.fromTo(element, duration, { opacity: 0, height: 0, y: -50 }, { opacity: 1, height: element.css('maxHeight'), y: 0, onComplete: done, ease: ease.easeOut });

            } else {
                done();
            }

        }
    };
});

coreFramework.directive('cfChecked', function ($compile) {
    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {

            if (!attrs['value']) {
                attrs.$set('ng-checked', '!' + attrs['ng-model']);
            }

            $compile(element.contents())(scope);

        }
    };
});

coreFramework.directive('cfFormStructure', function ($parse, $timeout) {

    function getFields (form) {
        var fields = null;
        angular.forEach(form, function (field, key) {
            if (key.indexOf('$') != 0 && field && field.$name && field.$name != form.$name) {
                fields = fields || {};
                fields[key] = getFields(field);
            }
        });
        if (!fields) {
            angular.forEach(form, function (field, key) {
                if (key.indexOf('$') != 0 && field && field.$name) {
                    fields = fields || {};
                    fields[key] = getFields(field);
                }
            });
        }
        if (fields && Object.keys(fields).length == 1) {
            fields = fields[Object.keys(fields)[0]];
        }

        return fields;

    };

    return {
        restrict: 'A',
        require: 'form',
        link: function (scope, element, attrs, ctrl) {
            
            var modelName = attrs['cfFormStructure'];

            if (modelName) {
                $timeout(function () {
                    var model = $parse(modelName);
                    model.assign(scope, getFields(ctrl));
                });
            }

        }
    };
});

coreFramework.directive('cfSearchScope', function (cfScopeCollection) {

    return {
        restrict: 'A',
        link: function (scope, element, attrs, ctrl) {
            attrs.$observe('cfSearchScope', function (value) {
                if (value) {
                    scope.searchScope = cfScopeCollection.get(value);
                }
            });

        }
    };
});

coreFramework.service('cfLocationService', function ($location, $timeout, $parse) {

    function setModelFunc (scope, modelName, queryString) {
        scope.$watch(modelName, function (value, oldValue) {
            if (value != oldValue && $location.search()[queryString] !== value) {
                $timeout(function () {
                    if (value) {
                        $location.path($location.path().split('/', 3).concat(['list', '']).join('/'));
                    }
                    $location.search(queryString, value || null);
                });
            }
        });

        scope.$on('$locationChangeStart', function () {
            updateModel(scope, modelName, queryString);
        });

        updateModel(scope, modelName, queryString);
    }
    
    function updateModel (scope, modelName, queryString) {
        if ($location.search()[queryString] !== scope[modelName]) {
            $timeout(function () {
                var model = $parse(modelName);
                    model.assign(scope, $location.search()[queryString]);
            });
        }
    }

    this.bindParam = setModelFunc;

});

coreFramework.service('cfSearchEnginePersistService', function ($location, $timeout, $parse) {

    window.searches = {};

    function setModelFunc (scope, modelName, queryString, module) {

        return;

        // scope.$watch(modelName, function (value, oldValue) {
        //     var module = getModuleName();
        //     if (value && searches[module] !== value) {
        //         console.log('module:' + module, 'modelName:' + modelName, 'val:' + value, 'oldVal:' + oldValue, 'searches:' + searches);
        //         searches[module] = value;
        //     }
        // });

        scope.$on('$locationChangeStart', function () {
            $timeout(function () {
                var module = getModuleName();
                if (scope[modelName]) {
                    searches[module] = scope[modelName];
                }
            });
        });

        scope.$on('$locationChangeSuccess', function () {
            updateModel(scope, modelName, queryString);
        });
    }
    
    function updateModel (scope, modelName, queryString) {
        var module = getModuleName();
        if (searches[module] !== scope[modelName]) {
            $timeout(function () {
                var model = $parse(modelName);
                model.assign(scope, searches[module]);
            });
        }
    }

    function getModuleName () {
        return $location.path().split('/admin/')[1].replace(/\/$/, '').split('/')[0];
    }

    this.bindParam = setModelFunc;
});

coreFramework.service('cfScopeCollection', function ($rootScope) {

    var scopes = {};

    function getScope (name) {

        if (!scopes[name]) {
            scopes[name] = $rootScope.$new();
        }

        return scopes[name];

    }

    this.get = getScope;

});

coreFramework.directive('cfLocationBindParam', function (cfLocationService) {

    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {

            cfLocationService.bindParam(scope, attrs.ngModel, attrs.cfLocationBindParam || 'query');

        },
    };
});

coreFramework.directive('cfChangeSegmented', function ($parse, $rootScope, $timeout) {

    var forceAsyncEvents = {
        'blur': true
    };
    var eventList = 'keydown blur click change k-change';
    var keydownCodes = [13, 32, 9];

    return {
        link: function (scope, element, attrs) {
            scope.copyObject = function (value) {
                return angular.copy(value);
            };
            var fn = $parse(attrs.cfChangeSegmented);
            element.on(eventList, function(event) {
                if (event.type == 'keydown' && keydownCodes.indexOf(event.keyCode) < 0) {
                    return;
                }
                var callback = function() {
                    fn(scope, { $event: event });
                };
                if (forceAsyncEvents[event.type] && $rootScope.$$phase) {
                    scope.$evalAsync(callback);
                } else {
                    $timeout(callback);
                }
            });
        }
    };

});


coreFramework.filter('cfTokenizer', function () {

    function parseValue (value) {
        if (value) {
            if (angular.isString(value)) {
                if (value.match(/\W/gmi)) {
                    value = value.replace(/^(.+)$/gmi, '\"$1\"');
                }
            } else if (angular.isObject(value)) {
                angular.forEach(value, function (val, key) {
                    value[key] = parseValue(val);
                });
            }
        }
        return value;
    };

    function formatValue (value) {
        if (value) {
            if (angular.isString(value)) {
                value = value.replace(/^(\")(.+)(\")$/gmi, '$2');
            } else if (angular.isObject(value)) {
                angular.forEach(value, function (val, key) {
                    value[key] = formatValue(val);
                });
            }
        }
        return value;
    };

    return function (input, filters, reverse) {
        
        var filtered;

        filtered = {
            query: '',
            tokens: {}
        };

        if (!input) {
            return filtered;
        }

        if (reverse) {
            filtered = '';
            angular.forEach(input.tokens, function (value, key) {
                if (value){
                    value = String(value);
                    if (value != '') {
                        if (value.indexOf(' ') >= 0) {
                            // value = '"' + value + '"';
                        }
                        filtered += key + ':' + parseValue(value) + ' ';
                    }
                }
            });
            filtered = filtered.substring(0, filtered.length - 1);
            filtered += input.query ? (filtered ? ' ' : '') + input.query : '';

            return filtered;
        }

        if (!filters) {
            filters = [];
        }
        if (angular.isObject(filters)) {
            filters = Object.keys(filters);
        }
        
        // matches: nonwhitespace, nonwhitespace:'anything', nonwhitespace:nonwhitespace
        // var matches = ('' + input).match(/(\S+:((".+?("))|(\S+)))|\S+/gmi);
        var matches = ('' + input).match(/\b((\w+?\:)((\w+)|(([\(\"].*?[\)\"])(\S*[\)\"]*))))|(\S+)/gmi);
        var query = [];
        var tokens = {};

        angular.forEach(matches, function (match) {
            var isToken = false;
            if (match.indexOf(':') > 0 && match.indexOf(':') < match.length - 1) {
                var pair = match.split(':');
                
                var key = pair.shift();

                if (filters.length) {
                    angular.forEach(filters, function (filter) {
                        if (filter == key) {
                            isToken = true;
                        }
                    });
                } else {
                    isToken = true;
                }

                // removes quotes from begining and end
                var value = formatValue(pair.join(':'));//.replace(/^(")(.+)(")$/gmi, '$2');
            }

            if (isToken) {
                if (value) {
                    tokens[key] = value;
                }
            } else {
                query.push(match);
            }
        });

        filtered.query = query.join(' ');
        filtered.tokens = tokens;

        return filtered;
    };
});

coreFramework.directive('cfDecorateQuotes', function ($compile) {

    function parseValue (value) {
        if (value) {
            if (angular.isString(value)) {
                if (value.match(/\W/gmi)) {
                    value = value.replace(/^(.+)$/gmi, '\"$1\"');
                }
            } else if (angular.isObject(value)) {
                angular.forEach(value, function (val, key) {
                    value[key] = parseValue(val);
                });
            }
        }
        return value;
    };

    function formatValue (value) {
        if (value) {
            if (angular.isString(value)) {
                value = value.replace(/^(\")(.+)(\")$/gmi, '$2');
            } else if (angular.isObject(value)) {
                angular.forEach(value, function (val, key) {
                    value[key] = formatValue(val);
                });
            }
        }
        return value;
    };

    return {
        restrict: 'A',
        require: 'ngModel',
        link: function (scope, element, attrs, ctrl) {

            ctrl.$parsers.unshift(parseValue);

            ctrl.$formatters.unshift(formatValue);

        }
    };
});
