<!DOCTYPE html>
<html>

  <head>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" data-semver="3.1.1" data-require="bootstrap-css@3.1.1" />
    <link data-require="animate.css@*" data-semver="1.0.0" rel="stylesheet" href="//rawgithub.com/daneden/animate.css/master/animate.min.css" />
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js" data-semver="1.2.17" data-require="angular.js@1.2.17"></script>
    <script data-require="jquery@*" data-semver="2.1.1" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js" data-semver="3.1.1" data-require="bootstrap@*"></script>
    <script src="https://code.angularjs.org/1.2.17/angular-animate.js" data-semver="1.2.17" data-require="angular-animate@*"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="app.js"></script>
    <script src="controller.js"></script>
    <script src="service.js"></script>
    <script src="directive.js"></script>
  </head>

  <body ng-app="app">
    <br />
    <div class="container">
      <div class="main-container" ng-controller="MainController">
        <sb-element-price data="segment.totalPrice"></sb-element-price>
        <ul>
          <segment-builder-group class="group-conditions level-0" level="1" data="dataMainGroup"></segment-builder-group>
        </ul>
      </div>
    </div>
    <script id="segmentBuilderGroupTpl" type="text/ng-template">
            <li>
                <div class="options">
                    <p>Relation: <group-relation data="data.relation"></group-relation></p>
                    <button ng-click="addElement('criterion')" class="btn btn-xs btn-primary">+CRITERE</button>
                    <button ng-click="addElement('segment')" class="btn btn-xs btn-primary">+SEGMENT</button>
                    <button ng-click="addElement('group')" class="btn btn-xs btn-primary">+GROUP</button>
                    <button ng-click="deletePlease({id: data.id})" class="btn btn-xs btn-danger align-right" ng-if="level > 1"><span class="glyphicon glyphicon-trash"></span></button>
                    <button ng-click="duplicatePlease({id: data.id})" class="btn btn-xs btn-primary align-right" ng-if="level > 1"><span class="glyphicon glyphicon-tags"></span></button>
                </div>
                <ul ng-show="data.elements.length > 0">
                    <li ng-repeat="element in data.elements | orderBy:'position'"
                        class="level-{{ level }}"
                        ng-class="{true:'li-group group-conditions', false:'li-condition'}[element.type == 'group']">
                        <div ng-switch="element.type">
                            <div ng-switch-when="segment">
                                <segment-builder-segment data="element" delete-please="deleteElement(id)" duplicate-please="duplicateElement(id)"></segment-builder-segment>
                            </div>
                            <div ng-switch-when="criterion">
                                <segment-builder-criterion data="element" delete-please="deleteElement(id)" duplicate-please="duplicateElement(id)"></segment-builder-criterion>
                            </div>
                            <div ng-switch-when="group">
                                <segment-builder-element data="element" 
                                                         level="level+1"
                                                         delete-please="deleteElement(id)" 
                                                         duplicate-please="duplicateElement(id)"></segment-builder-element>
                            </div>
                        </div>
                    </li>
                </ul>
                <div ng-if="data.elements.length == 0">
                    <h4 class="empty-group">Please add a criterion, a segment, or an other group.</h4>
                </div>
            </li>
        </script>
  </body>

</html>

$border_radius_custom: 4px;

@mixin animation($properties) {
    -webkit-animation: $properties;
    -moz-animation: $properties;
    -ms-animation: $properties;
    -o-animation: $properties;
    animation: $properties;
}

@mixin transition($properties...) {
    -webkit-transition: $properties;
    -moz-transition: $properties;
    -ms-transition: $properties;
    -o-transition: $properties;
    transition: $properties;
}

@mixin box-shadow($properties...) {
    -moz-box-shadow: $properties;
    -webkit-box-shadow: $properties;
    -o-box-shadow: $properties;
    box-shadow: $properties;
}


/***********************************************************************/

.container {
    width: 100%;
}

.main-container {
    display: block;
    width: 100%;
    //background: yellow;
    padding: 10px;
    
    input {
      width: 50px !important;
      padding: 2px;
      height: 22px;
    }
    select {
      width: 60px !important;
      padding: 3px;
      height: 22px;
    }
    
    ul {
        list-style: none;
        padding: 0;
        margin: 0 0 0 20px;
    }
    & > ul {
      margin: 0;
    }
    
    .group-conditions {
        position: relative;
        display: block;
        min-height: 60px;
        border-radius: $border_radius_custom;
        margin: 5px;
        padding: 5px;
        
        $color_start: #f5f3f4;
        $color_hover_start: #F4F4F4;
        @for $i from 0 through 15 {
            $darken_value: min(($i + 1) * 6, 100);
            $darken_value_more: min($darken_value + 8, 100);
            $darken_value_more_more: min($darken_value + 20, 100);
            
            &.level-#{$i} {
                background: darken($color_start, $darken_value);
                border: 1px solid darken($color_start, $darken_value_more);
                @include box-shadow(inset 0px 0px 10px 0px darken($color_start, $darken_value_more_more));
		        
		        &:hover {
/* 	                background: darken($color_hover_start, $darken_value); */
                    border-color: #666666;
		        }
                
                .options {
                    border-bottom: 1px solid darken($color_start, $darken_value_more);
                }
            }
        }
        
        span.glyphicon-hand-right {
            cursor: move;
        }
        
        .empty-group {
            text-align: center;
        }
    }
    
    .options {
        p,
        button {
            display: inline-block;
        }
        
        select {
            width: 100px;
            display: inline-block;
        }
    }
    
    .condition {
        display: block;
        margin: 5px;
        padding: 5px;
        border-radius: $border_radius_custom;
        border: 1px solid darken(#63535B, 15);
        background: #63535B;
        color: #ffffff;
        
        input,
        select {
	        width: 100px;
        }
        
        &.drag-in-progress {
            background: pink;
        }
    }
    
    button.align-right {
        float: right;
    }
       
    .drag-in-progress {
        pointer-events: none;
        background: green;
    }
    
    .drop-in-progress {
        background: yellow;
        border: 4px dashed blue;
        
        &:after {
            display: block;
            width: 50px;
            height: 50px;
            background: blue;
        }
    }
    
    .li-group {
        position: relative;
    }
    
    .li-condition,
    .li-group {
        &.ng-enter {
            @include animation(fadeInRight 0.4s);
            
        }
        &.ng-leave {
            @include animation(fadeOut 0.4s);
        }
    }
    
    .threshold {
        &.ng-hide-add {
            @include animation(fadeOut 0.4s);
        }
        &.ng-hide-remove {
            @include animation(fadeIn 0.4s);
        }
    }
}

span.special-info {
    position: absolute;
    left: -300px;
    
    background: yellow;
}


var app = angular.module('app', ['ngAnimate']);

app.controller('MainController', function($scope, $rootScope, SegmentBuilder) {
  
    $scope.titi = 'Test 3';
    
    $scope.segment = {
        totalPrice: SegmentBuilder.getCurrentSegmentPrice()
    };
    
    $scope.dataMainGroup = SegmentBuilder.currentSegment;
    
    $scope.$on(SegmentBuilder.events.name, function(event, type) {
        console.log('segmentBuilderEvent - event = ', event, ' / type = ', type);
        
        switch(type) {
            case SegmentBuilder.events.type.UPDATE_PRICE:
                $scope.segment.totalPrice = SegmentBuilder.getCurrentSegmentPrice();
                break;
            case SegmentBuilder.events.type.OPEN_SEGMENT_SELECTOR:
                //
                break;
            case SegmentBuilder.events.type.OPEN_DATAPOINT_SELECTOR:
                //
                break;
        }
        
    });
    
});

app.directive("segmentBuilderGroup", function() {
    return {
        restrict: "E",
        replace: true,
        scope: {
            data: '=',
            level: '=',
            duplicatePlease: '&',
            deletePlease: '&'
        },
        templateUrl:  'segmentBuilderGroupTpl',
        controller: function($scope, $rootScope, SegmentBuilder) {
            
            var getPositionNewElement = function() {
                var maxPositionValue = 0;
                angular.forEach($scope.data.elements, function(value, key) {
                    if(value.position > maxPositionValue) maxPositionValue = value.position;
                });
                return maxPositionValue + 1;
            }
            
            var getElement = function(id) {
                var elem = null;
                angular.forEach($scope.data.elements, function(value, key) {
                    if(value.id == id) elem = value;
                });
                return elem;
            }
            
            $scope.addElement = function(type) {
                var newElem,
                    newPosition = getPositionNewElement();
                
                switch(type) {
                    case 'criterion':
                        newElem = SegmentBuilder.getNewCriterion(newPosition);
                        break;
                    case 'segment':
                        newElem = SegmentBuilder.getNewSegment(newPosition);
                        break;
                    case 'group':
                        newElem = SegmentBuilder.getNewGroup(newPosition);
                        break;
                }
                $scope.data.elements.push(newElem);
                
                $rootScope.$broadcast(SegmentBuilder.events.name, SegmentBuilder.events.type.UPDATE_PRICE);
            }
            
            // id could be a criterion, segment, or group
            $scope.duplicateElement = function(id) {
                var element = getElement(id);
                
                if(element) {
                    var duplicate_element = SegmentBuilder.duplicateElement(element, getPositionNewElement());
                    $scope.data.elements.push(duplicate_element);
                }
                
                $rootScope.$broadcast(SegmentBuilder.events.name, SegmentBuilder.events.type.UPDATE_PRICE);
            }
            
            // id could be a criterion, segment, or group
            $scope.deleteElement = function(id) {
                var start = $scope.data.elements.length - 1;
                for(var i = start; i >= 0; i--) {
                    if($scope.data.elements[i].id === id) {
                        $scope.data.elements.splice(i, 1);
                    }
                }
                
                $rootScope.$broadcast(SegmentBuilder.events.name, SegmentBuilder.events.type.UPDATE_PRICE);
            }
        },
    };
});

app.directive("segmentBuilderElement", function($compile) {
    return {
        restrict: "E",
        replace: true,
        scope: {
            data: '=',
            level: '=',
            duplicatePlease: '&',
            deletePlease: '&'
        },
        template: '',
        link: function (scope, element, attrs) {
            var subElementsString = '<segment-builder-group data="data"\
                                                            level="level"\
                                                            delete-please="deletePlease({id: data.id})"\
                                                            duplicate-please="duplicatePlease({id: data.id})"></segment-builder-group>';
            
            if (angular.isArray(scope.data.elements)) {       
                $compile(subElementsString)(scope, function(cloned, scope) {
                    element.append(cloned); 
                });
            }
        },
        controller: function($scope) {}
    };
});

app.directive('groupRelation', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '='
        },
        template:  '<span>\
                        <select ng-model="data"\
                                ng-options="item.value as item.name for item in listRelation"\
                                class="form-control input-sm">\
                        </select>\
                    </span>',
        controller: function($scope, SegmentBuilder) {
            $scope.listRelation = SegmentBuilder.groupInfo.relation;
        },
        link: function(scope, element, attrs) {}
    };
});


app.directive('segmentBuilderCriterion', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '=',
            duplicatePlease: '&',
            deletePlease: '&'
        },
        template:  '<div class="condition form-inline">\
                        <sb-criterion-selector data="data.criterion"></sb-criterion-selector>\
                        <sb-criterion-operator data="data.operator"></sb-criterion-operator>\
                        <sb-criterion-value data="data.value"></sb-criterion-value>\
                        <sb-criterion-mode data="data.mode"></sb-criterion-mode>\
                        <sb-criterion-threshold data1="data.thresholdValue" data2="data.thresholdUnit" ng-show="showThreshold()"></sb-criterion-threshold>\
                        <sb-criterion-recency data="data.recency"></sb-criterion-recency>\
                        <sb-element-price data="data.criterion.price"></sb-element-price>\
                        <button ng-click="deletePlease({id: data.id})" class="btn btn-xs btn-danger align-right"><span class="glyphicon glyphicon-trash"></span></button>\
                        <button ng-click="duplicatePlease({id: data.id})" class="btn btn-xs btn-primary align-right"><span class="glyphicon glyphicon-tags"></span></button>\
                    </div>',
        controller: function($scope) {
            
            $scope.showThreshold = function() {
                return ['at_least_one', 'none', 'all'].indexOf($scope.data.mode) < 0;
            }
        },
        link: function(scope, element, attrs) {}
    };
});


app.directive('sbCriterionSelector', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '='
        },
        template:  '<span>\
                        <input type="text" class="form-control input-sm" name="name" ng-model="data.name"/>\
                    </span>',
        controller: function($scope) {},
        link: function(scope, element, attrs) {}
    };
});

app.directive('sbCriterionOperator', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '='
        },
        template:  '<span>\
                        <select ng-model="data"\
                                ng-options="item.value as item.name for item in listOperator"\
                                class="form-control input-sm">\
                        </select>\
                    </span>',
        controller: function($scope, SegmentBuilder) {
            $scope.listOperator = SegmentBuilder.criterionInfo.operator;
        },
        link: function(scope, element, attrs) {}
    };
});

app.directive('sbCriterionValue', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '='
        },
        template:  '<span>\
                        <input type="text" class="form-control input-sm" name="name" ng-model="data"/>\
                    </span>',
        controller: function($scope) {},
        link: function(scope, element, attrs) {}
    };
});

app.directive('sbCriterionMode', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '='
        },
        template:  '<span>\
                        <select ng-model="data"\
                                ng-options="item.value as item.name for item in listMode"\
                                class="form-control input-sm">\
                        </select>\
                    </span>',
        controller: function($scope, SegmentBuilder) {
            $scope.listMode = SegmentBuilder.criterionInfo.mode;
        },
        link: function(scope, element, attrs) {}
    };
});

app.directive('sbCriterionThreshold', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data1: '=',
            data2: '='
        },
        template:  '<span class="threshold">\
                        <input type="text" class="form-control input-sm" name="name" ng-model="data1"/>\
                        <select ng-model="data2"\
                                ng-options="item.value as item.name for item in listThresholdUnit"\
                                class="form-control input-sm">\
                        </select>\
                    </span>',
        controller: function($scope, SegmentBuilder) {
            $scope.listThresholdUnit = SegmentBuilder.criterionInfo.thresholdUnit;
        },
        link: function(scope, element, attrs) {}
    };
});

app.directive('sbCriterionRecency', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '='
        },
        template:  '<span>\
                        <input type="text" class="form-control input-sm" name="recency" ng-model="data"/>\
                    </span>',
        controller: function($scope) {},
        link: function(scope, element, attrs) {}
    };
});

app.directive('sbElementPrice', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '='
        },
        template:  '<span>\
                        <span class="label label-info">{{ data | currency }}</span>\
                    </span>',
        controller: function($scope) {},
        link: function(scope, element, attrs) {}
    };
});

app.directive('segmentBuilderSegment', function() {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            data: '=',
            duplicatePlease: '&',
            deletePlease: '&'
        },
        template:  '<div class="condition form-inline">\
                        <span>SEGMENT: {{ data.id }}</span>\
                        <input type="text" class="form-control input-sm" name="name" ng-model="data.segment.name"/>\
                        <element-price data="data.segment.price"></element-price>\
                        <button ng-click="deletePlease({id: data.id})" class="btn btn-xs btn-danger align-right"><span class="glyphicon glyphicon-trash"></span></button>\
                        <button ng-click="duplicatePlease({id: data.id})" class="btn btn-xs btn-primary align-right"><span class="glyphicon glyphicon-tags"></span></button>\
                    </div>',
        controller: function($scope) {},
        link: function(scope, element, attrs) {}
    };
});

app.factory('SegmentBuilder', function() {
    
    var criterionInfo = {
        operator: [
            {value:'contains',      name:'contains'},
            {value:'equals',        name:'equals (case insensitive)'},
            {value:'regexp',        name:'regular expression'},
            {value:'starts_with',   name:'starts with'},
            {value:'ends_with',     name:'ends with'},
            {value:'upper_than',    name:'upper than'},
            {value:'lesser_than',   name:'lesser than'}
        ],
        mode: [
            {value:'at_least_one',                      name:'at least once'},
            {value:'none',                              name:'none'},
            {value:'all',                               name:'all'},
            {value:'equals',                            name:'='},
            {value:'upper_than_n_percent',              name:'>'},
            {value:'lesser_than_n_percent',             name:'<'},
            {value:'upper_than_n_percent_or_equal',     name:'>='},
            {value:'lesser_than_n_percent_or_equal',    name:'<='}
        ],
        thresholdUnit: [
           {value:'percent',    name:'%'},
           {value:'unit',       name:'times'}
        ]
    };
    
    var groupInfo = {
      relation: [
          {value:'and',    name:'And'},
          {value:'or',     name:'Or'},
          {value:'none',   name:'None'}
      ]
    };
    
    var events = {
        name: 'segmentBuilderEvent',
        type: {
            UPDATE_PRICE: 'UPDATE_PRICE',
            OPEN_SEGMENT_SELECTOR: 'OPEN_SEGMENT_SELECTOR',
            OPEN_DATAPOINT_SELECTOR: 'OPEN_DATAPOINT_SELECTOR'
        }
    };

    var new_element = {
        criterion: {
            position: -1,
            type: 'criterion',
            id: '-1',
            criterion: {id: '987864', name: 'Resolution', code: 'a.g.r', price: 650000},
            operator: 'ends_with',
            value: '',
            mode: 'at_least_one',
            thresholdValue: 0,
            thresholdUnit: 'percent',
            recency: 0
        },
        segment: {
            position: -1,
            type: 'segment',
            id: '-1',
            segment: {id: '648648', name: 'segment bien bien bien', price: 544000}
        },
        group: {
            position: -1,
            type: 'group',
            id: '-1',
            relation: 'and',
            elements: []
        }
    };
    
    var currentSegmentDetail = {
        position: 1,
        type: 'group',
        id: 'group35848',
        relation: 'and',
        elements: [
            {
                position: 1,
                type: 'criterion',
                id: 'criterion65848',
                criterion: {id: '754564', name: 'Gender', code: 'v.f.g', price: 60000},
                operator: 'contains',
                value: 'homme',
                mode: 'equals',
                thresholdValue: 12,
                thresholdUnit: 'unit',
                recency: 12
            },
            {
                position: 4,
                type: 'group',
                id: 'group8979',
                relation: 'or',
                elements: [
                    {
                        position: 6,
                        type: 'group',
                        id: 'group2316',
                        relation: 'and',
                        elements: []
                    },
                    {
                        position: 4,
                        type: 'segment',
                        id: 'segment871528',
                        segment: {id: '847616', name: 'segment de la muerte', price: 84000}
                    },
                    {
                        position: 1,
                        type: 'group',
                        id: 'group21384',
                        relation: 'or',
                        elements: [
                            {
                                position: 1,
                                type: 'segment',
                                id: 'segment819954',
                                segment: {id: '51655', name: 'the segment xyz', price: 9100}
                            },
                            {
                                position: 3,
                                type: 'criterion',
                                id: 'criterion87195',
                                criterion: {id: '54159', name: 'Keyword', code: 's.w.w', price: 156000},
                                operator: 'equals',
                                value: 'toto',
                                mode: 'upper_than_n_percent_or_equal',
                                thresholdValue: 51,
                                thresholdUnit: 'unit',
                                recency: 51
                            }
                        ]
                    }
                ]
            },
            {
                position: 2,
                type: 'segment',
                id: 'segment8944',
                segment: {id: '7568468', name: 'mon segment toto', price: 42000}
            },
            {
                position: 3,
                type: 'group',
                id: 'group54614',
                relation: 'and',
                elements: []
            },
            {
                position: 12,
                type: 'criterion',
                id: 'criterion68789',
                criterion: {id: '7413235', name: 'Browser', code: 's.w.b', price: 10000},
                operator: 'ends_with',
                value: 'opera',
                mode: 'atLeastOnce',
                thresholdValue: 0,
                thresholdUnit: 'time',
                recency: 100
            },
        ]
    };
    
    
    
    var getNewCriterion = function(position) {
        var criterion = angular.copy(new_element.criterion);
        criterion.id = 'criterion' + Math.floor((Math.random()*100000)+1);
        criterion.position = position;
        return criterion;
    };
    
    var getNewSegment = function(position) {
        var segment = angular.copy(new_element.segment);
        segment.id = 'segment' + Math.floor((Math.random()*100000)+1);
        segment.position = position;
        return segment;
    };
    
    var getNewGroup = function(position) {
        var group = angular.copy(new_element.group);
        group.id = 'group' + Math.floor((Math.random()*100000)+1);
        group.position = position;
        return group;
    };
    
    
    
    var resetAllIdInThisGroup = function(elements) {
        angular.forEach(elements, function(element, key){
            element.id = element.type + Math.floor((Math.random()*100000)+1);
            
            if(element.type == 'group') {
                resetAllIdInThisGroup(element.elements);
            }
        });
    };
    
    
    
    var duplicateElement = function(element, position) {
        var duplicate_element = angular.copy(element);
        duplicate_element.id = duplicate_element.type + Math.floor((Math.random()*100000)+1);
        duplicate_element.position = position;
        
        if(duplicate_element.type == 'group') {
            resetAllIdInThisGroup(duplicate_element.elements);
        }
        
        return duplicate_element;
    };
    
    
    
    var getGroupPrice = function(group) {
        var price = 0;
        
        angular.forEach(group.elements, function(element, key) {
            switch(element.type) {
                case 'criterion':
                    price += element.criterion.price;
                    break;
                case 'segment':
                    price += element.segment.price;
                    break;
                case 'group':
                    price += getGroupPrice(element);
                    break;
            }
        });
        return price;
    };
    
    var getCurrentSegmentPrice = function() {
        return getGroupPrice(currentSegmentDetail);
    };

    return {
        getNewCriterion: getNewCriterion,
        getNewSegment: getNewSegment,
        getNewGroup: getNewGroup,
        duplicateElement: duplicateElement,
        criterionInfo: criterionInfo,
        groupInfo: groupInfo,
        currentSegment: currentSegmentDetail,
        getCurrentSegmentPrice: getCurrentSegmentPrice,
        events: events
    };
});