
(function($) {

Drupal.behaviors.archibaldPer = {

  attach: function(context, settings) {
    var $modal = $('#archibald-per-modal');
    if (!$modal.length) {
      $('body').append('<div id="archibald-per-modal"></div>');
    }
  }

};

Drupal.behaviors.archibaldCurricula.hooks.appReady.push(function(app) {
  // Is this one of our apps?
  if (
    typeof app.curriculum === 'undefined' ||
    app.curriculum !== 'per'
  ) {
    return;
  }

  // Hijack the item:select event.
  var oldItemSelectEventHandler = app.settings.events["item:select"];
  app.settings.events["item:select"] = function(item, columnCollection, column) {
    // We hijack this event. If the item is an objective, we don't trigger
    // the core event handler.
    if (item.get('type') !== 'objectifs') {
      oldItemSelectEventHandler(item, columnCollection, column);
    }
  };

  // When an objective is rendered, remove the has-children modifier class.
  app.on('column:item:render', function(itemModel, itemView, columnCollection, columnView) {
    if (itemModel.get('type') === 'objectifs') {
      itemView.$el.removeClass(itemView.className + '--has-children');
    }
  });

  // For progression items, open a jQuery UI dialog.
  var openModal = function(itemModel, itemView, columnCollection, column, eventApp) {
    if (itemModel.get('type') === 'objectifs') {
      if (
        typeof itemModel.get('data') !== 'undefined' &&
        typeof itemModel.get('data').perTable !== 'undefined'
      ) {
        var $window = $(window),
            $wrapper = $('<div class="archibald-per-modal"></div>'),
            $table = $('<table class="archibald-per-table"></table>'),
            perTable = itemModel.get('data').perTable,
            $row, $cell, cellContent;

        $wrapper.append($table);

        for (var rowId in perTable) {
          $row = $('<tr></tr>');
          for (var cellId in perTable[rowId]) {
            $cell = $('<td class="archibald-per-table__cell"></td>');
            $cell.addClass( 'archibald-per-table__cell--' + perTable[ rowId ][ cellId ].type );

            if ( typeof perTable[ rowId ][ cellId ].level !== 'undefined' ) {
              $cell.addClass( 'archibald-per-table__cell--level-' + perTable[ rowId ][ cellId ].level );
            }

            $cell.attr({
              colspan: typeof perTable[ rowId ][ cellId ].colspan !== 'undefined' ?
                perTable[ rowId ][ cellId ].colspan :
                1,
              rowspan: typeof perTable[ rowId ][ cellId ].rowspan !== 'undefined' ?
                perTable[ rowId ][ cellId ].rowspan :
                1
            });

            cellContent = '';
            _.each( perTable[ rowId ][ cellId ].content, function( item ) {
              cellContent += '<div class="archibald-per-table__cell__item">';

              if ( perTable[ rowId ][ cellId ].isSelectable ) {
                var model = app.getItemDatabase().get( item.id ),
                    checked = model ? model.get( 'active' ) : false;
                cellContent += '<label><input value="model-' + item.id + '" type="checkbox" ' + ( checked ? ' checked="checked"' : '' ) + ' /> ';

                cellContent += item.value;
                cellContent += '</label>';
              }
              else {
                cellContent += item.value;
              }
              cellContent += '</div>';
            } );
            $cell.html( cellContent );

            if ( perTable[ rowId ][ cellId ].isSelectable ) {
              (function( $cell ) {
                $cell.find( 'input' ).change( function() {
                  // Upon checking an item, actually select the
                  // corresponding model.
                  var $this = $( this );
                  if ( $this.val() ) {
                    var model = app.getItemDatabase().get( $this.val().replace( 'model-', '' ) );
                    model.set( 'active', $this.is( ':checked' ) );
                    app.recursiveCheck( model, app.settings.recursiveCheckPrompt );
                  }

                  // As long as one item is selected, highlight the whole
                  // cell.
                  if ( $cell.find( 'input:checked' ).length ) {
                    $cell.addClass( 'archibald-per-table__cell--active' );
                  } else {
                    $cell.removeClass( 'archibald-per-table__cell--active' );
                  }
                }).change();
              })( $cell );
            }

            $row.append( $cell );
          }
          $table.append( $row );
        }

        $( '#archibald-per-modal' ).empty().html( $wrapper ).dialog({
          height: $window.height() - 100,
          width: $window.width() - 400,
          position: { my: 'center center-50px', at: 'center', of: app.getWrapper() },
          show: 100,
          appendTo: eventApp.getWrapper(),
          buttons: [{
            text: "OK",
            click: function() {
              $( this ).dialog( 'close' );
            }
          }]
        });
      }
    }
  };

  var dependencyCheck = function( item, prompt ) {
    prompt = !!prompt;

    // If there are no dependencies, simply ignore.
    if (
      typeof item.get( 'dependencies') === 'undefined' ||
      !item.get( 'dependencies').length
    ) {
      return;
    }

    var dependency;
    for (var i = item.get( 'dependencies').length - 1; i >= 0; --i ) {
      dependency = app.getItemDatabase().get( item.get( 'dependencies')[i] );
      if ( dependency ) {
        // If our item is active, activate the dependency.
        if ( item.get( 'active' ) ) {
          dependency.set( 'active', true );
        } else {
          // Check if, for any our dependency, there are no longer any
          // dependents active. If so, we deactivate the dependency.
          var dependents = app.getItemDatabase().filter(function( model ) {
            return (
              model.get( 'active' ) &&
              typeof model.get( 'dependencies') !== 'undefined' &&
              model.get( 'dependencies' ).indexOf( dependency.get( 'id' ) ) !== -1
            );
          });

          if ( !dependents.length ) {
            // No more active dependents. Deactivate.
            dependency.set( 'active', false );
          }
        }

        // This is recursive.
        dependencyCheck( dependency );
      }
    }
  };

  app.on( 'column:item:render', function( itemModel, itemView, columnCollection, column, eventApp ) {
    if (
      typeof itemModel.get('data') !== 'undefined' &&
      typeof itemModel.get('data').level !== 'undefined'
    ) {
      itemView.$el.addClass( itemView.className + '--level-' + itemModel.get('data').level );
    }

    if ( itemModel.get('type') === 'objectifs' ) {
      itemView.$el.append( '\
<div class="archibald-column__wrapper__list__item__per-selection">\
<a>Sélectionner progressions d\'apprentissage&hellip;</a>\
</div>\
' );
      itemView.$el.find( '.archibald-column__wrapper__list__item__per-selection a' ).click(function( e ) {
        e.stopPropagation();
        openModal( itemModel, itemView, columnCollection, column, eventApp );
      });
    }
  });

  app.getItemDatabase().on('change:active', function(itemModel) {
    dependencyCheck(itemModel, true);
  });

  app.on('column:item:change', function(itemModel, itemView, columnCollection, column, eventApp) {
    if (
      typeof itemModel.get('data') !== 'undefined' &&
      typeof itemModel.get('data').isSelectable !== 'undefined' &&
      !itemModel.get('data').isSelectable &&
      itemModel.get('active')
    ) {
      itemModel.set('active', false);
    }
  });

  // If the selected item is a "progression d'apprentissage", core will
  // not scroll to it. Trigger that logic ourselves.
  app.on( 'summary:item:select search:select', function( selectedItem, collection, view ) {
    if ( selectedItem.get('type') === 'progressions' ) {
      var timeOut = 100;

      // @todo Make this a method of the View itself!
      if ( typeof $.fn.nanoScroller !== 'undefined' ) {
        var $element = app.getWrapper().find( '[data-model-id="' + selectedItem.get( 'parentId' ) + '"]' );
        if ( $element.length ) {
          // @todo Too much hardcoded stuff!!
          $element.parents( '.archibald-column' ).find( '.nano' ).nanoScroller({
            scrollTo: $element
          });

          setTimeout( function() {
            $element.find( '.archibald-column__wrapper__list__item__per-selection a' ).click();
          }, 400 );
          timeOut = 600;
        }
      }

      // Scroll the dialog as well. Give the dialog some time to open up and
      // render.
      setTimeout( function() {
        $('#archibald-per-modal').stop().animate({
          scrollTop: ( $( '#archibald-per-modal' ).find( '[value="model-' + selectedItem.get( 'id' ) + '"]' ).offset().top - 100 ) + 'px'
        });
      }, timeOut );
    }
  } );

  app.on( 'search:results', function( results, collection ) {
    // Many objectives have the same name. Add cycle information so we can
    // distinguish them, unless the element has an objective code.
    var item;
    for (var i = results.length - 1; i >= 0; --i ) {
      item = collection.get( results[i].value );
      if (
        item &&
        typeof item.get('data') !== 'undefined' &&
        typeof item.get('data').perCode === 'undefined' &&
        typeof item.get('data').cycle !== 'undefined'
       ) {
        results[i].label += ' (cycle ' + item.get('data').cycle + ')';
      }
    }
  } );

  // Some data may already be available. Trigger the dependency check.
  _.each(app.getItemDatabase().where({
    active: true
  }), function(item) {
    dependencyCheck(item, false);
  });
});

})(jQuery);
