'use strict';

var directive = {};

directive.runnableExample = ['$templateCache', '$document', function($templateCache, $document) {
  var exampleClassNameSelector = '.runnable-example-file';
  var doc = $document[0];
  var tpl =
    '<nav class="runnable-example-tabs" ng-if="tabs">' +
    '  <a ng-class="{active:$index==activeTabIndex}"' +
         'ng-repeat="tab in tabs track by $index" ' +
         'href="" ' +
         'class="btn"' +
         'ng-click="setTab($index)">' + 
    '    {{ tab }}' +
    '  </a>' +
    '</nav>';

  return {
    restrict: 'C',
    scope : true,
    controller : ['$scope', function($scope) {
      $scope.setTab = function(index) {
        var tab = $scope.tabs[index];
        $scope.activeTabIndex = index;
        $scope.$broadcast('tabChange', index, tab);
      };
    }],
    compile : function(element) {
      element.html(tpl + element.html());
      return function(scope, element) {
        var node = element[0];
        var examples = node.querySelectorAll(exampleClassNameSelector);
        var tabs = [], now = Date.now();
        angular.forEach(examples, function(child, index) {
          tabs.push(child.getAttribute('name'));
        });

        if(tabs.length > 0) {
          scope.tabs = tabs;
          scope.$on('tabChange', function(e, index, title) {
            angular.forEach(examples, function(child) {
              child.style.display = 'none';
            });
            var selected = examples[index];
            selected.style.display = 'block';
          });
          scope.setTab(0);
        }
      }
    }
  };
}];

directive.dropdownToggle =
          ['$document', '$location', '$window',
  function ($document,   $location,   $window) {
    var openElement = null, close;
    return {
      restrict: 'C',
      link: function(scope, element, attrs) {
        scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() {
          close && close();
        });

        element.parent().on('click', function(event) {
          close && close();
        });

        element.on('click', function(event) {
          event.preventDefault();
          event.stopPropagation();

          var iWasOpen = false;

          if (openElement) {
            iWasOpen = openElement === element;
            close();
          }

          if (!iWasOpen){
            element.parent().addClass('open');
            openElement = element;

            close = function (event) {
              event && event.preventDefault();
              event && event.stopPropagation();
              $document.off('click', close);
              element.parent().removeClass('open');
              close = null;
              openElement = null;
            }

            $document.on('click', close);
          }
        });
      }
    };
  }];

directive.syntax = function() {
  return {
    restrict: 'A',
    link: function(scope, element, attrs) {
      function makeLink(type, text, link, icon) {
        return '<a href="' + link + '" class="btn syntax-' + type + '" target="_blank" rel="nofollow">' + 
                '<span class="' + icon + '"></span> ' + text +
               '</a>';
      };

      var html = '';
      var types = {
        'github' : {
          text : 'View on Github',
          key : 'syntaxGithub',
          icon : 'icon-github'
        },
        'plunkr' : {
          text : 'View on Plunkr',
          key : 'syntaxPlunkr',
          icon : 'icon-arrow-down'
        },
        'jsfiddle' : {
          text : 'View on JSFiddle',
          key : 'syntaxFiddle',
          icon : 'icon-cloud'
        }
      };
      for(var type in types) {
        var data = types[type];
        var link = attrs[data.key];
        if(link) {
          html += makeLink(type, data.text, link, data.icon);
        }
      };

      var nav = document.createElement('nav');
      nav.className = 'syntax-links';
      nav.innerHTML = html;

      var node = element[0];
      var par = node.parentNode;
      par.insertBefore(nav, node);
    }
  }
}

directive.tabbable = function() {
  return {
    restrict: 'C',
    compile: function(element) {
      var navTabs = angular.element('<ul class="nav nav-tabs"></ul>'),
          tabContent = angular.element('<div class="tab-content"></div>');

      tabContent.append(element.contents());
      element.append(navTabs).append(tabContent);
    },
    controller: ['$scope', '$element', function($scope, $element) {
      var navTabs = $element.contents().eq(0),
          ngModel = $element.controller('ngModel') || {},
          tabs = [],
          selectedTab;

      ngModel.$render = function() {
        var $viewValue = this.$viewValue;

        if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) {
          if(selectedTab) {
            selectedTab.paneElement.removeClass('active');
            selectedTab.tabElement.removeClass('active');
            selectedTab = null;
          }
          if($viewValue) {
            for(var i = 0, ii = tabs.length; i < ii; i++) {
              if ($viewValue == tabs[i].value) {
                selectedTab = tabs[i];
                break;
              }
            }
            if (selectedTab) {
              selectedTab.paneElement.addClass('active');
              selectedTab.tabElement.addClass('active');
            }
          }

        }
      };

      this.addPane = function(element, attr) {
        var li = angular.element('<li><a href></a></li>'),
            a = li.find('a'),
            tab = {
              paneElement: element,
              paneAttrs: attr,
              tabElement: li
            };

        tabs.push(tab);

        attr.$observe('value', update)();
        attr.$observe('title', function(){ update(); a.text(tab.title); })();

        function update() {
          tab.title = attr.title;
          tab.value = attr.value || attr.title;
          if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) {
            // we are not part of angular
            ngModel.$viewValue = tab.value;
          }
          ngModel.$render();
        }

        navTabs.append(li);
        li.on('click', function(event) {
          event.preventDefault();
          event.stopPropagation();
          if (ngModel.$setViewValue) {
            $scope.$apply(function() {
              ngModel.$setViewValue(tab.value);
              ngModel.$render();
            });
          } else {
            // we are not part of angular
            ngModel.$viewValue = tab.value;
            ngModel.$render();
          }
        });

        return function() {
          tab.tabElement.remove();
          for(var i = 0, ii = tabs.length; i < ii; i++ ) {
            if (tab == tabs[i]) {
              tabs.splice(i, 1);
            }
          }
        };
      }
    }]
  };
};

directive.table = function() {
  return {
    restrict: 'E',
    link: function(scope, element, attrs) {
      if (!attrs['class']) {
        element.addClass('table table-bordered table-striped code-table');
      }
    }
  };
};

var popoverElement = function() {
  var object = {
    init : function() {
      this.element = angular.element(
        '<div class="popover popover-incode top">' +
          '<div class="arrow"></div>' +
          '<div class="popover-inner">' +
            '<div class="popover-title"><code></code></div>' +
            '<div class="popover-content"></div>' +
          '</div>' +
        '</div>'
      );
      this.node = this.element[0];
      this.element.css({
        'display':'block',
        'position':'absolute'
      });
      angular.element(document.body).append(this.element);

      var inner = this.element.children()[1];
      this.titleElement   = angular.element(inner.childNodes[0].firstChild);
      this.contentElement = angular.element(inner.childNodes[1]);

      //stop the click on the tooltip
      this.element.bind('click', function(event) {
        event.preventDefault();
        event.stopPropagation();
      });

      var self = this;
      angular.element(document.body).bind('click',function(event) {
        if(self.visible()) self.hide();
      });
    },

    show : function(x,y) {
      this.element.addClass('visible');
      this.position(x || 0, y || 0);
    },

    hide : function() {
      this.element.removeClass('visible');
      this.position(-9999,-9999);
    },

    visible : function() {
      return this.position().y >= 0;
    },

    isSituatedAt : function(element) {
      return this.besideElement ? element[0] == this.besideElement[0] : false;
    },

    title : function(value) {
      return this.titleElement.html(value);
    },

    content : function(value) { 
      if(value && value.length > 0) {
        value = marked(value);
      }
      return this.contentElement.html(value);
    },

    positionArrow : function(position) {
      this.node.className = 'popover ' + position;
    },

    positionAway : function() {
      this.besideElement = null;
      this.hide();
    },

    positionBeside : function(element) {
      this.besideElement = element;

      var elm = element[0];
      var x = elm.offsetLeft;
      var y = elm.offsetTop;
      x -= 30;
      y -= this.node.offsetHeight + 10;
      this.show(x,y);
    },

    position : function(x,y) {
      if(x != null && y != null) {
        this.element.css('left',x + 'px');
        this.element.css('top', y + 'px');
      }
      else {
        return {
          x : this.node.offsetLeft,
          y : this.node.offsetTop
        };
      }
    }
  };

  object.init();
  object.hide();

  return object;
};

directive.popover = ['popoverElement', function(popover) {
  return {
    restrict: 'A',
    priority : 500,
    link: function(scope, element, attrs) {
      element.bind('click',function(event) {
        event.preventDefault();
        event.stopPropagation();
        if(popover.isSituatedAt(element) && popover.visible()) {
          popover.title('');
          popover.content('');
          popover.positionAway();
        }
        else {
          popover.title(attrs.title);
          popover.content(attrs.content);
          popover.positionBeside(element);
        }
      });
    }
  }
}];

directive.tabPane = function() {
  return {
    require: '^tabbable',
    restrict: 'C',
    link: function(scope, element, attrs, tabsCtrl) {
      element.on('$remove', tabsCtrl.addPane(element, attrs));
    }
  };
};

directive.foldout = ['$http', '$animate','$window', function($http, $animate, $window) {
  return {
    restrict: 'A',
    priority : 500,
    link: function(scope, element, attrs) {
      var container, loading, url = attrs.url;
      if(/\/build\//.test($window.location.href)) {
        url = '/build/docs' + url;
      }
      element.bind('click',function() {
        scope.$apply(function() {
          if(!container) {
            if(loading) return;

            loading = true;
            var par = element.parent();
            container = angular.element('<div class="foldout">loading...</div>');
            $animate.enter(container, null, par);

            $http.get(url, { cache : true }).success(function(html) {
              loading = false;

              html = '<div class="foldout-inner">' +
                      '<div calss="foldout-arrow"></div>' +
                      html +
                     '</div>';
              container.html(html);

              //avoid showing the element if the user has already closed it
              if(container.css('display') == 'block') {
                container.css('display','none');
                $animate.addClass(container, 'ng-hide');
              }
            });
          }
          else {
            container.hasClass('ng-hide') ? $animate.removeClass(container, 'ng-hide') : $animate.addClass(container, 'ng-hide');
          }
        });
      });
    }
  }
}];

angular.module('bootstrap', [])
  .directive(directive)
  .factory('popoverElement', popoverElement)
  .run(function() {
    marked.setOptions({
      gfm: true,
      tables: true
    });
  });
