'use strict';

angular.module('689Cloud')

    // Checkbox directive ( iCheck { checkbox & radio })
    // #mycheck
    .directive('mycheck', ['$parse', function ($parse) {

        return {
            restrict: "A",
            replace: true,
            transclude: false,
            compile: function (attrs) {

                return function (scope, element, attrs) {

                    var modelAccessor = $parse(attrs.ngModel);

                    switch (attrs.type) {

                        case 'checkbox':

                            element.iCheck({
                                checkboxClass: 'icheckbox_minimal-blue',
                                aria: true
                            });

                            break;

                        case 'radio':

                            element.iCheck({
                                radioClass: 'iradio_minimal-blue',
                                aria: true
                                // handle: 'radio'
                            });

                            break;
                    }

                    // We are using iCheck plug-in
                    if (attrs.ngModel) {

                        element.on('ifToggled', function () {

                            scope.$apply(function () {

                                // Change bound variable
                                modelAccessor.assign(scope, element.prop('checked'));

                            });
                        });
                    }

                    // I think we shouldn't watch this
                    scope.$watch(modelAccessor, function () {

                        //console.log( element.prop( 'checked' ) )
                        element.iCheck('update');

                    }, true);

                };
            }

        };
    }])

    // Spinner component (jQuery UI)
    .directive('myspinner', ['$parse', function ($parse) {

        return {
            restrict: "A",
            replace: true,
            transclude: false,
            //        scope: {
            //
            //            spinnerModel: '=' // I set it on element
            //
            //        },
            compile: function () {

                return function (scope, element, attrs) {

                    var modelAccessor = $parse(attrs.ngModel);

                    var min = parseInt((attrs.minValue) ? attrs.minValue : 1),
                        max = parseInt((attrs.maxValue) ? attrs.maxValue : 100);

                    element.spinner({
                        'min': min,
                        'max': max,
                        'stop': function (event, ui) {

                            scope.$apply(function () {

                                // Change bound variable
                                var value = element.spinner("value");

                                if (value > max)
                                    value = max;

                                if (value <= min)
                                    value = min;

                                modelAccessor.assign(scope, value);

                                // I assign to spinner model
                                // scope.spinnerModel = value;

                            });
                        }
                    });
                };
            }
        };
    }])

    // Datepicker ( jQuery UI )
    // #mydatepicker
    .directive('mydatepicker', ['$parse', 'session', function ($parse, session) {
        return {
            restrict: "A",
            replace: true,
            transclude: false,
            compile: function () {

                return function (scope, element, attrs) {

                    var modelAccessor = $parse(attrs.ngModel);

                    var processChange = function (dateText) {

                        // var date = element.datepicker("getDate");
                        scope.$apply(function () {
                            // Change bound variable
                            modelAccessor.assign(scope, dateText);
                        });
                    };

                    var opts = {
                        autoSize: true,
                        // Datepicker is now using format ISO 8601
                        dateFormat: 'mm/dd/yy', //  app.CALENDAR_FORMAT ||
                        // onClose: processChange,
                        onSelect: processChange
                    };

                    // Get min date if have
                    var min = attrs.minDate;

                    if (min) {
                        opts.minDate = new Date(min);
                    }

                    // apply
                    element.datepicker(opts);
                };
            }
        };
    }])

    // Tooltip ( Tooltipster plug-in )
    .directive('mytip', ['$parse', 'util', function ($parse, util) {

        function getTextWidth(text) {

            if (text === undefined || text === null)
                return 0;

            var html = '<span>' + text + '</span>';

            var sensor = $(html).css({margin: 0, padding: 0});

            $('body').append(sensor);

            var width = sensor.width();

            sensor.remove();

            return width;
        }

        function getTextLength(text) {

            return text.length;
        }

        return {
            restrict: "A",
            replace: true,
            transclude: false,
            compile: function () {

                return function (scope, element, attrs) {

                    // Content of tip
                    var text = (attrs.mytipI18n) ? util.translate(attrs.mytipI18n) : attrs.mytip;

                    // Update lang
                    var opts = {
                        content: text,
                        position: (attrs.mytipPlacement) ? attrs.mytipPlacement : 'top',
                        // multiple: true,
                        contentAsHTML: true
                        // debug: false
                    };

                    // Create tooltip
                    element.tooltipster(opts);

                    var anchorLength = attrs.mytipShowWhen;
                    var textLength = attrs.mytipLimitLength;

                    if (anchorLength) {

                        element.tooltipster('disable');

                        if (anchorLength < getTextWidth(element.attr('mytip'))) {

                            element.tooltipster('enable');
                        }
                    } else if (textLength) {
                        element.tooltipster('disable');
                        if (Number(textLength) + 3 < getTextLength(element.attr('mytip'))) {
                            element.tooltipster('enable');
                        }
                    }

                    // When our tip is now using i18n as content
                    // Check tooltip when user changed their info
                    if (attrs.mytipI18n) {

                        scope.$on("i18nextLanguageChange", function (event, lang) {

                            element.tooltipster('update', util.translate(attrs.mytipI18n));
                        });
                    }

                    // Watch model
                    // Set tooltip from a model
                    if (attrs.mytipModel)
                        var modelAccessor = $parse(attrs.mytipModel);

                    scope.$watch(modelAccessor, function (n) {

                        if (n) {

                            if (anchorLength) {

                                // Allow show
                                if (anchorLength < getTextWidth(n)) {

                                    element.tooltipster('enable');
                                }
                            } else if (textLength) {

                                element.tooltipster('disable');


                                if (Number(textLength) + 3 < getTextLength(n)) {

                                    element.tooltipster('enable');
                                }
                            }
                            // Update content
                            element.tooltipster('update', n);
                        }
                    }, true);

                    //                 attrs.$observe( "mytip", function ( n, o ) {
                    //
                    //                 }, true );
                    //
                    //                 // Apply when language has been changed
                    //                 // This snippet can't execute when we set language as a resolver
                    //                 scope.$on( 'i18nextLanguageChange', function ( n, o ) {
                    //
                    //                     // Update content
                    //                     if ( n !== o )
                    //                        element.tooltipster( 'update', element.attr( 'mytip' ));
                    //                 });
                };
            }
        };
    }])

    // Validation engine
    .directive('myvalidate', function () {
        return {
            restrict: "A",
            replace: true,
            scope: {
                validate: '=validate',
                fnSubmit: '=validateSubmit'
                //currentDate: '=currentDate'
            },
            transclude: false,
            compile: function () {

                return function (scope, element, attrs) {

                    var opts = {
                        binded: false,
                        scroll: false,
                        validationEventTrigger: "",
                        onValidationComplete: function (e, status) {

                            if (scope.validate !== undefined)
                                scope.validate = status;

                            // Do submit
                            if (status) {

                                scope.fnSubmit();
                            }
                        }
                    };

                    element.validationEngine(opts);
                };
            }

        };
    })

    // Tag input
    .directive('mytokenfield', ['$timeout', '_', '$', 'AppUtil', function ($timeout, _, $, AppUtil) {

        return {
            restrict: "A",
            replace: true,
            transclude: false,
            scope: {
                tagSrc: '=tagSource',
                tokens: '=tokenObject',
                allowExt: '=allowExternal'
                //invalidFormat: '=invalidFormat'
            },
            compile: function () {

                return function (scope, element, attrs) {

                    //var modelAccessor = $parse(attrs.tokenObject);
                    function filterSource(list) {
                        return _.filter(list, function (f) {
                            return (_.findIndex(scope.tokens || [], {value: f.value, type: f.type}) === -1);
                        }) || [];
                    }

                    var opts = {
                        autocomplete: {
                            // appendTo: 'body',
                            source: []
                            // delay: 1000
                        },
                        showAutocompleteOnFocus: true,
                        createTokensOnBlur: true
                    };

                    // Get opts
                    if (attrs.minWidth) {

                        opts.minWidth = parseInt(attrs.minWidth);

                    }

                    scope.$on('$destroy', function () {

                        element.tokenfield('destroy');
                    });

                    element.tokenfield(opts);

                    // Watch tag src
                    scope.$watch('tagSrc', function (n, old) {

                        var o = {
                            autocomplete: {
                                source: filterSource(n) || [],
                                delay: 0
                            },
                            tokens: []
                        };

                        if (n !== old) {
                            // Destroy
                            element.tokenfield('destroy');

                            var t = $timeout(function () {

                                element.tokenfield(angular.extend({}, opts, o));

                                clearTimeout(t);

                            }); // Dont remove this timeout -  jQuery UI problem
                        }

                    }, true);

                    element.on('tokenfield:createdtoken', function (e) {

                        var parent = element.parent('.tokenfield');

                        if (!AppUtil.isValidEmail(e.attrs.value)) {
                            parent.find('.token-label').each(function () {
                                if ($(this).text() === e.attrs.value) {
                                    $(this).parent('.token').css({
                                        'border': '1px solid red',
                                        'background-color': '#FFCCCB'
                                    });
                                    //scope.invalidFormat = false;
                                    //scope.$apply();
                                }
                            });
                        } else {
                            // not allow external user
                            if (!scope.allowExt) {

                                var src = _.pluck(scope.tagSrc, 'value');
                                // not belong to source -> show error
                                if ($.inArray(e.attrs.value, src) === -1) {
                                    parent.find('.token-label').each(function () {
                                        if ($(this).text() === e.attrs.value)
                                            $(this).parent('.token').css({'border': '1px solid red'});

                                    });
                                    //return false;
                                }
                            }

                            // remove item in list source
                            if (_.contains(src, e.attrs.value)) {

                                _.remove(scope.tagSrc, e.attrs.value);

                            }
                        }
                        // Set value
                        scope.$apply(function () {

                            scope.tokens = element.tokenfield('getTokens');
                        });

                        // Update source
                        $('.token-input').autocomplete("option", "source", filterSource(scope.tagSrc));

                    });

                    // Implement event from token field
                    element.on('tokenfield:createtoken', function (e) {

                        var data = e.attrs.label.split('-');

                        // Check duplicate && invalid user form external
                        e.attrs.label = data[0] ? data[0] : data[1];

                        var tokens = element.tokenfield('getTokens'),
                            lValue = _.pluck(tokens, 'value');

                        var parent = element.parent('.tokenfield');

                        // Duplicate
                        // if ( $.inArray( e.attrs.value, lValue ) >= 0 ) {
                        if (_.findIndex(lValue, {value: e.attrs.value, type: e.attrs.type}) >= 0) {

                            // Noty error

                            var el = parent.find('.token-label').filter(function (i) {

                                return ($.trim($(this).text()) === $.trim(e.attrs.label)) ? true : false;

                            });

                            parent.find('.token-input').val('');

                            el.parent('.token').addClass('duplicate');

                            var t = $timeout(function () {

                                clearTimeout(t);

                                el.parent('.token').removeClass('duplicate');

                            }, 500);

                            return false;
                        }

                    });
                    //
                    element.on('tokenfield:removedtoken', function (e) {

                        scope.$apply(function () {

                            scope.tokens = element.tokenfield('getTokens');
                        });

                        $('.token-input').autocomplete("option", "source", filterSource(scope.tagSrc));
                    });
                };
            }

        };
    }])

    // seletepicker
    .directive('selectpicker', function () {

        return {
            restrict: "A",
            replace: true,
            transclude: false,
            compile: function () {

                return function (scope, element, attrs) {

                    var opts = {container: 'body', width: 'auto'};

                    if (attrs.width) {

                        opts.width = attrs.width;
                    }

                    element.selectpicker(opts);

                    if (attrs.selectedValue) {

                        element.selectpicker('val', attrs.selectedValue);

                    }

                    // Watcher
                    scope.$watch(attrs, function () {

                        element.selectpicker('val', attrs.selectedValue);

                        element.selectpicker('refresh');

                    });

                    scope.$on('$destroy', function () {
                        element.selectpicker('destroy');

                    });
                };
            }

        };

    })

    // selectboxit plugin
    .directive('selectbox', ['$', function ($) {

        return {
            restrict: "A",
            replace: true,
            scope: {
                model: '=ngModel'
            },
            transclude: false,
            compile: function () {

                return function (scope, element, attrs) {

                    var opt = {
                        theme: "bootstrap"
                    };

                    element.bind('change', function () {

                        scope.model = element.val();

                        scope.$apply();
                    });

                    element.selectBoxIt(opt);

                    if (attrs.selectedValue) {

                        element.val(attrs.selectedValue);

                        var selectBox = element.data("selectBox-selectBoxIt");

                        selectBox.refresh();
                    }

                    $("[rel='popover']").popover({trigger: "hover", container: "body"});

                    // Destroy
                    scope.$on('$destroy', function () {

                        selectBox.destroy();
                    });

                };
            }

        };
    }])

    // Dropdown
    .directive('mydropdown', ['$compile', function ($compile) {

        return {
            restrict: 'E',
            scope: {
                items: '=dropdownData',
                doSelect: '&selectVal',
                selectedItem: '=preselectedItem'
            },
            link: function (scope, element, attrs) {

                var html = '';
                switch (attrs.menuType) {
                    case "button":
                        html += '<button class="btn-group"><button class="btn button-label btn-info">Action</button><button class="btn btn-info dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>';
                        break;

                    case 'menu':
                        html += '<ul class="nav nav-pills"><li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown">Dropdown<b class="caret"></b></a>' +
                            '<ul class="dropdown-menu"><li ng-repeat="item in items"><a tabindex="-1" data-ng-click="selectVal(item)">{{item.name}}</a></li></ul>'

                            + '</li></ul>';
                        break;

                    default:
                        html += '<div class="dropdown"><a class="dropdown-toggle" role="button" data-toggle="dropdown" href="javascript:;">Dropdown<b class="caret"></b></a>';
                        break;
                }

                // html += '<ul class="dropdown-menu"><li ng-repeat="item in items"><a tabindex="-1" data-ng-click="selectVal(item)">{{item.name}}</a></li></ul></div>';

                element.append($compile(html)(scope));

                for (var i = 0; i < scope.items.length; i++) {
                    if (scope.items[i].id === scope.selectedItem) {
                        scope.bSelectedItem = scope.items[i];
                        break;
                    }
                }

                scope.selectVal = function (item) {

                    switch (attrs.menuType) {

                        case "button":
                            $('button.button-label', element).html(item.name);
                            break;

                        case 'menu':
                            $('a.dropdown-toggle', element).html('<b class="caret"></b> ' + item.name);
                            break;

                        default:
                            $('a.dropdown-toggle', element).html('<b class="caret"></b> ' + item.name);
                            break;
                    }
                    // A little difficult to understand
                    scope.doSelect({
                        selectedVal: item.id
                    });
                };

                scope.selectVal(scope.bSelectedItem);
            }
        };
    }])

    // Beautify date
    .directive('beautifydate', ['util', function (util) {

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

                // var modelAccessor = $parse(attrs.beautifydate);
                attrs.$observe("beautifydate", function (n) {

                    // element.text( n );
                    if (n) {
//                        moment.locale('vi');
                        // Using server time is the correct method in this case
                        // var sTime = attrs.serverTime;
                        var pretty = util.getMoment(n).fromNow();

                        console.log('pretty', pretty);
                        element.text(pretty);
                    }

                    // element.prettydate();
                }, true);
            }
        };
    }])

    // Items can be selected by using keyboard
    .directive("selectonic", function () {

        return {
            restrict: "A",
            scope: {
                opts: "&selectonicOpts"
            },
            link: function ($scope, element) {

                // We need to get opts

                $(element[0]).selectonic({
                    multi: true,
                    autoScroll: true,
                    mouseMode: "standard",
                    keyboard: true,
                    select: function (event, ui) {
                        // do something cool, for expample enable actions buttons
                        // console.log( ui );
                    },
                    unselectAll: function (event, ui) {
                        // …and disable actions buttons
                    }
                });

                // Scroll detect event
                // Resize event
                element.bind('scroll', function () {

                    // Reach the bottom
                    if ($(this).scrollTop() + $(this).innerHeight() + 10 >= this.scrollHeight) {

                        // Emit parent scope to load more event
                        $scope.$emit("$loadMoreEvents");
                    }
                });

                // Using appear item to get date from now
            }
        };
    })

    // Datatable directive
    .directive('datatable', ['app', '$timeout', 'checkbox', 'util', function (app, $timeout, checkbox, util) {

        return {
            restrict: "A",
            scope: {
                opts: '=datatableOpts', // Options
                dt: '=datatable'
            },
            replace: true,
            transclude: false,
            compile: function () {

                return function ($scope, element, attrs) {

                    var dom;
                    if ($scope.opts.state === "project") {
                        dom = '<"row dt-ctrl-wrapper"<"col-xs-12"l>><"row"<"col-xs-12"rt>><"row"p>';
                    } else {
                        dom = '<"row dt-ctrl-wrapper"<"col-xs-6"f><"col-xs-6"l>><"row"<"col-xs-12"rt>><"row dt-ctrl-wrapper"<"col-xs-5"><"col-xs-7"p>>';
                    }

                    var defaultOpts = {
                        "autoWidth": false,
                        // "dom": '<"dt-table-info hidden-xs"i>tr<"text-center"p>', // Hide info for mobile devices
                        //"dom": 'R<"row dt-ctrl-wrapper"<"col-sm-6"f><"col-sm-6 text-right"p>>rt',
                        // "dom": 'R<"row dt-ctrl-wrapper"<"col-sm-12"f>>rt<"row"p>',
                        "dom": dom,
                        "lengthChange": true,
                        // "searching": false,
                        "info": true,
                        "paging": true,
                        "pageLength": app.LIST_PAGE_SIZE || 10,
                        "serverSide": true,
                        "processing": true,
                        "language": {
                            "paginate": {
                                "next": ">",
                                "previous": "<",
                                "first": "<<",
                                "last": ">>"
                            },
                            //                        "info": util.translate('datatable.info'),
                            //                        "infoEmpty": util.translate('datatable.info_empty'),
                            "search": util.translate('datatable.emptyText'),
                            "searchPlaceholder": util.translate('tooltip.project.search'),
                            "emptyTable": util.translate('datatable.empty_table'),
                            "processing": "<div class='lds-ripple'><div></div><div></div></div>",
                            "lengthMenu": util.translate('datatable.length_menu')
                        },
                        "order": [2, 'asc'],
                        // Disable sort
                        "columnDefs": [
                            {'orderable': false, 'targets': [0, 1]}
                        ],
                        "rowCallback": function (row, data) {
                            // var s = angular.toJson( data ); // we can use JSON.stringtify()
                        }
                    };

                    // Apply datatable with given options

                    $scope.dt = element.DataTable(angular.extend({}, defaultOpts, $scope.opts));

                    $scope.$emit("$dtLoaded", $scope.dt);

                    // Reinit if the option has been changed
                    $scope.$on('$dtHasChanged', function (event, opt) {

                        // Destroy
                        $scope.dt && $scope.dt.destroy();

                        // Reinit
                        $scope.dt = element.DataTable(angular.extend({}, defaultOpts, opt || $scope.opts));

                    }, true);

                    // We can use a service to handle checkbox
                    $scope.$on('$destroy', function () {

                        // Cleanup the array
                        checkbox.cleanUp();
                    });
                };
            }
        };
    }])

    // Show error on form
    .directive('showErrors', ['$timeout', function ($timeout) {

        return {
            restrict: 'A',
            require: '^form',
            link: function (scope, el, attrs, formCtrl) {

                // find the text box element, which has the 'name' attribute
                var inputEl = el[0].querySelector("[name]");
                // convert the native text box element to an angular element
                var inputNgEl = angular.element(inputEl);
                // get the name on the text box
                var inputName = inputNgEl.attr('name');

                inputNgEl.bind('blur keyup', function () {
                    if (formCtrl[inputName]) {
                        el.toggleClass('has-error', formCtrl[inputName].$invalid);
                        // Set it as dirty when it's invalid
                        if (formCtrl[inputName].$invalid) {
                            formCtrl[inputName].$dirty = true;
                            // Notify that it's has changed
                            scope.$digest();
                        }
                    }
                });

                // Watch model
                scope.$watch(function () {
                    return formCtrl[inputName] ? formCtrl[inputName].$invalid : false;
                }, function (invalid) {
                    // Apply when dirty input
                    if (formCtrl[inputName] && !formCtrl[inputName].$dirty && invalid) {
                        return;
                    }
                    el.toggleClass('has-error', invalid);
                    // Green color
                    // el.toggleClass('has-success', !invalid);
                });

                // Apply check
                scope.$on('show-errors-check-validity', function () {
                    if (formCtrl[inputName]) {
                        // Set model as dirty
                        formCtrl[inputName].$dirty = true;
                        el.toggleClass('has-error', formCtrl[inputName].$invalid);
                    }
                });

                // Reset form
                scope.$on('show-errors-reset', function () {

                    $timeout(function () {

                        el.removeClass('has-error');

                    }, 0, false);
                });
            }
        };
    }])

    // Compare to another value
    // Such as confirm password
    .directive("compareTo", function () {

        return {
            require: "ngModel",
            scope: {
                otherModelValue: "=compareTo"
            },
            link: function (scope, element, attributes, ngModel) {

                ngModel.$validators.compareTo = function (modelValue) {

                    var cp = (modelValue === scope.otherModelValue.$modelValue);
                    ngModel.$setValidity('repeat', cp);
                    return cp;
                };

                scope.$watch("otherModelValue.$modelValue", function () {

                    ngModel.$validate();
                });
            }
        };
    })

    // Another way check repeat
    .directive("repeatPassword", function () {
        return {
            require: "ngModel",
            link: function (scope, elem, attrs, ctrl) {

                var otherInput = elem.inheritedData("$formController")[attrs.repeatPassword];

                ctrl.$parsers.push(function (value) {
                    if (value === otherInput.$viewValue) {
                        ctrl.$setValidity("repeat", true);
                        return value;
                    }
                    ctrl.$setValidity("repeat", false);
                    // ctrl.$invalid = false;
                });

                otherInput.$parsers.push(function (value) {
                    ctrl.$setValidity("repeat", value === ctrl.$viewValue);
                    // ctrl.$invalid = ( value === ctrl.$viewValue );
                    return value;
                });
            }
        };
    })

    // Convert HEX to char
    // E.g: \u003 => <
    .directive('escapeInput', ['util', function (util) {

        return {
            require: 'ngModel',
            link: function (scope, element, attrs, ngModelController) {

                //      ngModelController.$parsers.push( function( value ) {
                //        //convert data from view format to model format
                //        // return data; //converted
                //
                //      });

                ngModelController.$formatters.push(function (value) {

                    //convert data from model format to view format
                    // return data; //converted
                    if (!angular.isString(value))
                        return value;

                    // Convert them
                    value = util.convertHexToString(value);

                    // Escape
                    // ( value = util.escape( value ));
                    return value;
                });
            }
        };
    }])

    // Basic uploader
    .directive("basicUploader", ['session', '$', function (session, $) {

        return {
            // transclude: true,
            scope: {
                uploadApi: "=uploadApi",
                teamId: '=?teamId',
                onSuccess: "&",
                onError: "&",
                maskInputClass: "@"
            },
            restrict: "E",
            replace: true,
            templateUrl: "templates/basic_uploader.html",
            link: function (scope, element, attrs) {

                if (!angular.isObject(scope.uploadApi))
                    return;

                // Create a template for that
                //            var tmpl = '<form enctype="multipart/form-data" method="POST">'+
                //                            '<input type="file"/>'+
                //                        '</form>';
                //
                //            element = element.html( tmpl );

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

                // Get url from obj
                var URL = scope.uploadApi.name || scope.uploadApi.url;

                var cb = scope.onSuccess, error = scope.onError;

                var form = element, $file = $(element.find("input[type=file]"));

                // Set id
                // But should use a random number
                $file.attr("id", "basicInputFile");

                // Submit form
                form.submit(function (e) {

                    e.preventDefault();

                    var data = {
                        auth_token: session.getToken()
                    };

                    if (scope.teamId) {
                        data.team_id = scope.teamId;
                    }

                    $.ajaxFileUpload({
                        url: URL + "?time=" + new Date().getTime(),
                        secureuri: false,
                        fileElementId: $file.attr("id"),
                        data: data,
                        dataType: 'json',
                        success: function (data) {

                            cb && cb({data: data});
                        },
                        error: function (data) {
                            error && error({error: data});
                        }
                    });

                    $file = $(element.find("input[type=file]"));

                    // Clear
                    $file.replaceWith($file.val('').clone(true));

                    bindChange();
                });

                // Bind change input file
                function bindChange() {

                    // When change input
                    $(element.find("input[type=file]")).unbind("change").on("change", function () {

                        form.trigger("submit");
                    });
                }

                bindChange();
            }
        };
    }])

    .directive('icheck', ['$timeout', '$parse', function ($timeout, $parse) {
        return {
            require: 'ngModel',
            link: function ($scope, element, $attrs, ngModel) {
                return $timeout(function () {
                    var value;
                    value = $attrs['value'];

                    $scope.$watch($attrs['ngModel'], function (newValue) {
                        $(element).iCheck('update');
                    });

                    $scope.$watch($attrs['ngDisabled'], function (newValue) {
                        $(element).iCheck('update');
                    });

                    return $(element).iCheck({
                        checkboxClass: 'icheckbox_flat-blue',
                        radioClass: 'iradio_flat-blue'

                    }).on('ifChanged', function (event) {
                        if ($(element).attr('type') === 'checkbox' && $attrs['ngModel']) {
                            $scope.$apply(function () {
                                return ngModel.$setViewValue(event.target.checked);
                            });
                        }
                        if ($(element).attr('type') === 'radio' && $attrs['ngModel']) {
                            return $scope.$apply(function () {
                                return ngModel.$setViewValue(value);
                            });
                        }
                    });
                });
            }
        };
    }])

    .directive('icheckTable', ['$timeout', '$parse', function ($timeout, $parse) {
        return {
            link: function ($scope, element, $attrs) {
                return $timeout(function () {
                    var value;
                    value = $attrs['value'];

                    $(element).on('tblUpdateCheckbox', function () {
                        $(element).iCheck('update');
                    });

                    return $(element).iCheck({
                        checkboxClass: 'icheckbox_flat-blue',
                        radioClass: 'iradio_flat-blue'

                    }).on('ifChanged', function (event) {
                        $(element).change();
                    });
                });
            }
        };
    }])

    .directive('icheckBasic', ['$timeout', '$parse', function ($timeout, $parse) {
        return {
            link: function ($scope, element, $attrs) {
                return $timeout(function () {
                    var value;
                    value = $attrs['value'];

                    return $(element).iCheck({
                        checkboxClass: 'icheckbox_flat-blue',
                        radioClass: 'iradio_flat-blue'

                    }).on('ifChanged', function (event) {
                        $(element).click();
                    });
                });
            }
        };
    }])

    .directive('infiniteScroll', [
        '$rootScope', '$window', '$timeout', function ($rootScope, $window, $timeout) {
            return {
                link: function (scope, elem, attrs) {

                    var checkWhenEnabled, handler, scrollDistance, scrollEnabled;
                    $window = angular.element($window);
                    scrollDistance = 0;
                    if (attrs.infiniteScrollDistance !== null) {
                        scope.$watch(attrs.infiniteScrollDistance, function (value) {
                            return scrollDistance = value;
                        });
                    }
                    scrollEnabled = true;
                    checkWhenEnabled = false;
                    if (attrs.infiniteScrollDisabled !== null) {
                        scope.$watch(attrs.infiniteScrollDisabled, function (value) {
                            scrollEnabled = !value;
                            if (scrollEnabled && checkWhenEnabled) {
                                checkWhenEnabled = false;
                                return elem.trigger('scroll');
                            }
                        });
                    }
                    elem.on('scroll', function () {
                        var elementBottom = $(this).scrollTop() + $(this).innerHeight();
                        var shouldScroll = elementBottom + 10 + scrollDistance >= this.scrollHeight;
                        if (shouldScroll && scrollEnabled) {
                            if ($rootScope.$$phase) {
                                return scope.$eval(attrs.infiniteScroll);
                            } else {
                                return scope.$apply(attrs.infiniteScroll);
                            }
                        } else if (shouldScroll) {
                            return checkWhenEnabled = true;
                        }
                    });
                    scope.$on('$destroy', function () {
                        return $window.off('scroll');
                    });
                }
            };
        }])

    .directive('mention', ['$filter', '$sce', function ($filter, $sce) {
        return {
            restrict: 'A', // only activate on element attribute
            require: '?ngModel', // get a hold of NgModelController
            link: function (scope, element, attrs, ngModel) {
                if (!ngModel)
                    return; // do nothing if no ng-model

                // Specify how UI should be updated
                ngModel.$render = function () {
                    element.html(ngModel.$viewValue || '');
                };

                // Listen for change events to enable binding
                element.on('blur keyup change', function () {
                    scope.$apply(read);
                });
                read(); // initialize

                //format label name in view to @[email]
                ngModel.$parsers.push(function (value) {

                    value = value.replace(/<span(.*?)>(.*?)<\/span>/ig, function (m) {
                        var mentionUser = angular.element(m).data('mention');
                        var entity = '@[' + mentionUser + ']';
                        return '@[' + mentionUser + ']';
                    });

                    //convert html space to text space
                    value = value.replace(/&nbsp;/ig, ' ');
                    return value;
                });

                //format ngModel value to label name in view
                ngModel.$formatters.push(function (value) {

                    if (!value) {
                        return "";
                    }
                    var text = $sce.getTrustedHtml($filter('escape_text')(value, true));
                    text = text.replace(/@\[(.*?)]/gi, function (m) {
                        if (m) {
                            var member = getMemberByEmail(m.substr(2, m.length - 3));
                            if (member) {
                                return "<span data-mention='" + member.email_address + "' id='' class='mention-tag' contenteditable='false'>" + member.label + "</span>";

                            } else {
                                return m;
                            }
                        } else
                            return "";
                    });
                    return text;

                });

                //get member
                function getMemberByEmail(email) {
                    for (var i = 0; i < scope.project.member.length; i++) {
                        if (scope.project.member[i].email_address === email) {
                            return scope.project.member[i];
                        }
                    }
                }

                //allow to select all word
                if (attrs.selectNonEditable) {
                    element.bind('click', function (e) {
                        var range, sel, target;
                        target = e.toElement;
                        if (target !== this && angular.element(target).attr('contenteditable') === 'false') {
                            range = document.createRange();
                            sel = window.getSelection();
                            range.setStartBefore(target);
                            range.setEndAfter(target);
                            sel.removeAllRanges();
                            sel.addRange(range);
                        }
                    });
                }
                ;

                //convert div to textarea
                element.toTextarea({
                    allowHTML: true, //allow HTML formatting with CTRL+b, CTRL+i, etc.
                    allowImg: false, //allow drag and drop images
                    singleLine: false, //make a single line so it will only expand horiontally
                    pastePlainText: true//paste text without styling as source
                });


                // Write data to the model
                function read() {
                    var html = element.html();
                    // When we clear the content editable the browser leaves a <br> behind
                    // If strip-br attribute is provided then we strip this out
                    if (attrs.stripBr && html === '<br>') {
                        html = '';
                    }
                    ngModel.$setViewValue(html);
                }
            }
        };
    }])

    .directive('uploaderDirective', ['$timeout', 'plupload', '$', '_', 'AppUtil', 'util', 'APIStatus', '$state',
        'session', 'userConfig', '$stateParams', '$uibModal', 'APIName',
        function ($timeout, plupload, $, _, AppUtil, util, APIStatus, $state, session, userConfig, $stateParams,
                  $uibModal, APIName) {

            // randomString
            function randomString(len, charSet) {
                charSet = charSet || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
                var randomString = '';
                for (var i = 0; i < len; i++) {
                    var randomPoz = Math.floor(Math.random() * charSet.length);
                    randomString += charSet.substring(randomPoz, randomPoz + 1);
                }
                return randomString;
            }

            return {
                restrict: "AE",
                templateUrl: 'js/common/directives/uploader/upload_directive_tmpl.html',
                //transclude: true,
                scope: {
                    // Option setting
                    urlUpload: "@url",
                    label: "@label",
                    bttext: "@bttext",
                    filelist: "=filelist",
                    dragAndDropContainer: "@container",
                    maxfilesize: "=maxfilesize",
                    // File extension allow upload
                    extension: "@extension"
                    //
                },
                link: function (scope, element, attrs) {
                    // Max file size upload
                    var MAX_FILE_SIZE = scope.maxfilesize;
                    // URL Upload
                    var url_api_upload = scope.urlUpload;

                    // Create uploader
                    var uploader = {};

                    scope.btUploadId = randomString(5);

                    // I provide access to the file list inside of the directive. This can be
                    // used to render the items being uploaded.
                    scope.queue = [] || uploader.files; //new PublicQueue();

                    // Create info object contains some information about upload files
                    scope.uploading = false, scope.info = {current_file: {}, total: 0, uploaded: 0};

                    // Remove file from queue uploading
                    // @param {object} file
                    scope.cancelFile = function (file) {

                        var ids = [];

                        // Update status in queue
                        _.forEach(uploader.files, function (f) {

                            if (f.id == file.id) {
                                f.status = 6;
                                f.loaded = 0;
                                f.percent = 0;

                                ids.push(f.id);
                            }
                        });

                        doCancelUpload(ids);

                        // Stop
                        uploader.stop();

                        var files = _.filter(uploader.files, function (f) {

                            return f.status == plupload.QUEUED && f.id != file.id;
                        });

                        // Start new file
                        if (files.length > 0) {

                            uploader.start();
                        }
                    };

                    // Re-try upload file
                    // @param {object} file
                    scope.retry = function (file) {
                        _.forEach(uploader.files, function (f) {
                            if (f.id == file.id)
                                f.status = plupload.QUEUED;
                        });

                        var files = _.filter(uploader.files, {status: plupload.QUEUED});
                        if (files.length > 0 && isNotUploading()) {
                            uploader.start();
                        }
                    };
                    // Cancel all file
                    scope.cancelAll = function () {

                        if (isUploading()) {

                            uploader.stop();
                        }

                        var ids = [];

                        _.forEach(uploader.files, function (f) {

                            // Cancel when uploading or in queue
                            if (f.status == plupload.UPLOADING || f.status == plupload.QUEUED) {

                                f.loaded = 0;
                                f.percent = 0;
                                f.status = 6;
                                // Push to list
                                ids.push(f.id);
                            }
                        });

                        doCancelUpload(ids);
                    };
                    // Clean-up upload
                    scope.cleanUp = function () {

                        // Remove all
                        if (uploader) {

                            if (isNotUploading()) {
                                // Clean up
                                uploader.splice(0);
                                // Clean queue as well
                                scope.queue = [];
                            } else {

                                scope.cancelAll();
                            }
                        }

                        // Hide modal
                        element.find('#modal-upload').addClass('hid');
                    };
                    // Minimize upload modal
                    scope.minimize = function () {
                        // Hide modal
                        var m = element.find('#modal-upload');
                        m.toggleClass('minimize');
                    };
                    // Check window & container size
                    var $percentDOM = element.find('#current-percent');
                    // Handle resize window
                    window.addEventListener('resize', function () {
                        // Refresh uploader
                        uploader.refresh();
                    });

                    // Do cancel upload file
                    function doCancelUpload(ids) {
                        if (ids.length === 0)
                            return;
                        // TODO
                        // call API to request cancel
                    }

                    // Handle before call upload
                    function handleBeforeUpload(uploader, file) {
                        // Set params
                        scope.info.current_file = file;
                        uploader.settings.multipart_params.file_name = file.name;
                    }

                    // Handle error
                    function handleError(uploader, error) {

                        // We have to call cancel file
                        // Get file error
                        var f = error.file;
                        if (f) {
                            if (error.code === plupload.HTTP_ERROR) {
                                // Check valid
                                // Notify that this file is error
                                doCancelUpload([f.id]);
                            }
                            // Show error
                            showUploadError(f, error.code);
                        }
                    }

                    // Hanlde file added
                    function handleFilesAdded(uploader, files) {
                        // Get modal
                        var modal = element.find('#modal-upload');
                        // Remove minimize class
                        modal.removeClass('minimize');
                        if (modal.hasClass('hid'))
                            modal.removeClass('hid').css('display', 'none').slideDown('slow');
                        // Animiation
                        for (var i in files) {
                            scope.queue.push(files[i]);
                        }
                        var total = uploader.files.length + files.length;
                        // Set as total files
                        scope.info.total = total;
                        // Tell AngularJS that something has changed (the public queue will have
                        // been updated at this point).
                        scope.$apply();
                    }

                    //  Handle file uploaded
                    function handleFileUploaded(uploader, file, response) {
                        var currentUser = session.getUser();

                        scope.$apply(
                            function () {
                                var dataResponse = angular.fromJson(response.response);
                                // var results = dataResponse.data;
                                // var status = dataResponse.status;
                                // var message = "";
                                if (dataResponse.data) {
                                    if (dataResponse.data.error_list && dataResponse.data.error_list.length > 0) {
                                        return $uibModal.open({
                                                windowClass: 'bootstrap-dialog type-primary',
                                                backdrop: false,
                                                templateUrl: 'js/components/import_user/error_modal.html',
                                                controller: 'ErrorModal',
                                                resolve: {
                                                    data: dataResponse.data
                                                }
                                            }
                                        );
                                    } else if ((dataResponse.data.list_email_exists && dataResponse.data.list_email_exists.length > 0) ||
                                        (dataResponse.data.list_email_import && dataResponse.data.list_email_import.length > 0) ||
                                        (dataResponse.data.list_email_error && dataResponse.data.list_email_error.length > 0)) {
                                        if (dataResponse.data.list_email_exists.length === 0 && dataResponse.data.list_email_error.length === 0) {
                                            // call api import teams
                                            var params = {};
                                            params['company_id'] = currentUser.role_id === userConfig.SUPER_ADMIN.role ? $stateParams.id : currentUser.company_id;
                                            params['list_team'] = dataResponse.data.list_email_import;
                                            var objUrl = {
                                                url: APIName.CREATE_TEAM_FROM_CSV.name,
                                                method: APIName.CREATE_TEAM_FROM_CSV.method
                                            };

                                            AppUtil.createRequest(objUrl, params, function (response) {
                                                if (response.data.error_list.length > 0) {
                                                    return $uibModal.open({
                                                            windowClass: 'bootstrap-dialog type-primary',
                                                            backdrop: false,
                                                            templateUrl: 'js/components/import_user/error_modal.html',
                                                            controller: 'ErrorModal',
                                                            resolve: {
                                                                data: response.data
                                                            }
                                                        }
                                                    );
                                                } else {
                                                    AppUtil.showSuccess({
                                                        text: util.translate("label.team.import_success")
                                                    });
                                                    if ($state.current.name === "teamCreate") {
                                                        $state.go("teamList");
                                                    }
                                                    if ($state.current.name === "teamCreateBySuperAdmin") {
                                                        $state.go("companyProfile", {id: $stateParams.id});
                                                    }
                                                }
                                            }, function (error) {
                                                AppUtil.showError({
                                                    text: util.translate("sever_errors." + error.status)
                                                });
                                            });

                                        } else {
                                            return $uibModal.open({
                                                    windowClass: 'bootstrap-dialog type-primary',
                                                    backdrop: false,
                                                    templateUrl: 'js/components/import_user/list_email_modal.html',
                                                    controller: 'ListEmailModal',
                                                    resolve: {
                                                        data: function () {
                                                            return dataResponse.data;
                                                        },
                                                        company: function () {
                                                            return $stateParams.id;
                                                        }
                                                    }
                                                }
                                            );
                                        }
                                    } else {
                                        AppUtil.showSuccess({
                                            text: util.translate("label.team.import_success")
                                        });
                                        if (currentUser.role_id === userConfig.ADMIN.role ||
                                            currentUser.role_id === userConfig.MANAGER.role) {
                                            $state.go("userList");
                                        } else {
                                            $state.go("adminTeamProfile", {
                                                company_id: $stateParams.company_id,
                                                id: $stateParams.team_id
                                            });
                                        }
                                    }
                                } else {
                                    AppUtil.showError({text: util.translate("sever_errors." + dataResponse.status)});
                                    if (dataResponse.status === 401) {
                                        $state.go("adminLogin");
                                    }
                                }
                            }
                        );
                    }

                    // Handle process changed
                    function handleUploadProgress(uploader, file) {
                        if (isUploading()) {
                            scope.$apply(function () {
                                $percentDOM.removeClass('hid').text(file.percent + '%');
                                scope.$emit('UploadProgress', file.percent);
                            });
                        }
                    }

                    // Handle queue changed
                    function handleQueueChanged(uploader) {

                        // Find queue
                        var files = _.filter(uploader.files, {status: plupload.QUEUED});

                        if (files.length && isNotUploading()) {

                            uploader.start();
                        }

                        // Safe apply
                        $timeout(function () {

                            scope.$apply();
                        });
                    }

                    // Handle uploader's status changed
                    function handleStateChanged(uploader) {
                        var check = isUploading();
                        if (check) {
                            element.addClass("uploading");
                        } else {
                            element.removeClass("uploading");
                        }

                        // Safe apply
                        $timeout(function () {
                            scope.$apply(function () {
                                scope.uploading = check;
                                if (isUploading()) {
                                    $percentDOM.removeClass('hid');
                                } else {

                                    $percentDOM.addClass('hid');
                                }
                            });
                        });
                    }

                    // CHeck whether uploader is not uploading
                    function isNotUploading() {

                        return (uploader.state === plupload.STOPPED);
                    }

                    // Check whether is uploading
                    function isUploading() {

                        if (uploader)
                            return (uploader.state === plupload.STARTED);
                        else
                            return false;
                    }

                    function showUploadError(file, errorCode) {
                        // Handle upload error here
                        if (errorCode === -601) {
                            AppUtil.showError({
                                text: util.translate("sever_errors.1411")
                            });
                        } else {
                            AppUtil.showError({
                                text: util.translate("default_toast.invalid_data")
                            });
                        }
                    }

                    // Initialize Directive
                    function inititalize() {
                        $timeout(function () {
                            // Init plupload
                            console.log("uploader.init...");
                            uploader = new plupload.Uploader({
                                // Init Option setting for plUpload
                                // Document http://www.plupload.com/docs/v2/Options
                                runtimes: "html5,gears,browserplus,flash,html4",
                                multi_selection: false,
                                // Upload the image to the API.
                                url: url_api_upload,
                                max_file_size: MAX_FILE_SIZE + 'mb',
                                chunk_size: '1024kb',
                                autostart: true,
                                unique_names: true,
                                filters: [
                                    {title: 'Allow Files', extensions: scope.extension}
                                ],
                                // Set the name of file field (that contains the upload).
                                file_data_name: "file",
                                // The container, into which to inject the Input shim.
                                container: scope.dragAndDropContainer,
                                // The ID of the drop-zone element.
                                drop_element: scope.dragAndDropContainer,
                                // To enable click-to-select-files, you can provide a browse button.
                                // We can use the same one as the drop zone.
                                browse_button: scope.btUploadId,
                                // Flash source
                                flash_swf_url: 'libs/plupload/plupload.flash.swf',
                                // We don't have any parameters yet; but, let's create the object now
                                // so that we can simply consume it later in the BeforeUpload event.
                                multipart_params: {
                                    'Content-Type': 'multipart/form-data'
                                }

                            });

                            // Initialize the plupload runtime.
                            uploader.bind("Error", handleError);
                            uploader.bind("FilesAdded", handleFilesAdded);
                            uploader.bind("QueueChanged", handleQueueChanged);
                            uploader.bind("BeforeUpload", handleBeforeUpload);
                            uploader.bind("UploadProgress", handleUploadProgress);
                            uploader.bind("FileUploaded", handleFileUploaded);
                            uploader.bind("StateChanged", handleStateChanged);
                            // Run init
                            uploader.init();
                        }, 1500);
                    }

                    // Destroy directive
                    //
                    scope.$on("$destroy", function () {

                        // Destroy uploader
                        if (uploader)
                            uploader.destroy();

                        // Unbind what i binded
                        $('#container').unbind('dragenter dragleave drop');
                        scope.$destroy();
                        // Clean up
                        scope.queue = [];
                    });

                    scope.getThumnail = function (file) {
                        if (file.icon)
                            return file.icon;
                        else
                            return "images/doc-icon.png";
                    };

                    // Init
                    inititalize();
                }
            };
        }])

    .directive('blockMaxLength', ['$parse', function ($parse) {
        return {
            scope: {
                blockInputLength: '='
            },
            link: function (scope, elm, attrs) {
                elm.bind('keypress', function (e) {
                    console.log('keypress', elm[0].value);

                    if (elm[0].value.length >= scope.blockInputLength) {
                        e.preventDefault();
                        return false;
                    }
                });
            }
        }
    }])
