
// Requires objectSearch.js from DWR and prototype.js
window.cmsControllers = new Array();


var SearchWidgetController = Class.create();
SearchWidgetController.prototype = {
  searchFieldId: null,
  searchResultsId: null,
  types: null,
  keyPressTimeout: null,
  previousQuery: null,
  queriesRequested: null,
  searchCount: 0,

  initialize: function( searchField, searchResults, types )
  {
    this.searchFieldId = searchField;
    this.searchResultsId = searchResults;

    $(searchField).onkeyup = this.search.bind(this);

    if ( types != null )
    {
      var typeList = types.split(',');
      for ( var i=0;i < typeList.length; i++ )
        typeList[i] = 'type:' + typeList[i];
     this.types = typeList.join(' ');
    }
  },

  search: function()
  {
    var query = $(this.searchFieldId).value;
    if (( this.previousQuery == null ) || ( query != this.previousQuery ))
    {
      if ( this.keyPressTimeout != null )
        clearTimeout( this.keyPressTimeout );

      this.keyPressTimeout = setTimeout( this.doSearch.bind(this), 200 );
    }
  },

  doSearch: function()
  {
    var query = $(this.searchFieldId).value
    if ( query )
    {
      $('spinner').show();
      var subQuery = query;
      if ( query.indexOf(':') < 0 )
        subQuery = 'identifier:(' + query + '*) label:(' + query + '*) body:(' + query + '*)';

      if ( this.types != null )
        subQuery = '+(' + this.types + ') AND +(' + subQuery + ')';
      objectSearch.search( subQuery, { callback:     this.handleSearch.bind(this, query),
                                    errorHandler: this.clearResults.bind(this) } );
    }
  },

  handleSearch: function( query, results )
  {
    $('spinner').hide();
    // ignored if results don't represent current query
    if ( query != $(this.searchFieldId).value )
      return;

    var options = $(this.searchResultsId).options;
    options.length = 0;
    if ( results.length > 0 )
    {
      for ( var i=0; i < results.length; i++ )
      {
        var newOption = new Option( results[i].label, results[i].type + ':::' + results[i].identifier );
        newOption.title = results[i].type + '/' + results[i].identifier;
        options[options.length] = newOption;
      }
    }
  },

  clearResults: function( message )
  {
    var options = $(this.searchResultsId).options;
    options.length = 0;
  }
};

var SearchPageController = Class.create();
SearchPageController.prototype = {
  searchFieldId:    null,
  typeFieldId:      null,
  currentCountId:   null,
  keyPressTimeout:  null,
  typeLinkMap:      null,
  currentType:      null,
  previousQuery:    null,
  serachURL:        null,
  overMenuClass:    null,

  initialize: function( searchFieldId, formId, searchButtonId, typeFieldId,
                        currentCountId, currentType, typeLinkMap, searchURL, overMenuClass )
  {
    this.searchFieldId = searchFieldId;
    this.typeFieldId = typeFieldId;
    this.formId = formId;
    this.typeLinkMap = typeLinkMap;
    this.currentCountId = currentCountId;
    this.currentType = currentType;
    this.searchURL = searchURL;
    this.overMenuClass = overMenuClass;

    $(searchButtonId).onclick = this.submit.bind(this);
    $(searchFieldId).onkeyup = this.preview.bind(this);
    $(this.formId).onsubmit = this.updateFormAction.bind(this);
    for ( var type in typeLinkMap )
    {
      $(typeLinkMap[type][0]).onclick = this.changeType.bind(this, type);
      $(typeLinkMap[type][0]).onmouseover = this.overdiv.bind(this,typeLinkMap[type][0]);
      $(typeLinkMap[type][0]).onmouseout = this.outdiv.bind(this,typeLinkMap[type][0]);
    }

    this.doPreview();
  },

  overdiv: function( elementId )
  {
    Element.addClassName($(elementId), this.overMenuClass);
  },

  outdiv: function( elementId )
  {
    Element.removeClassName($(elementId), this.overMenuClass);
  },

  submit: function()
  {
    this.updateFormAction();
    $(this.formId).submit();
    return false;
  },

  updateFormAction: function()
  {
    var url = this.searchURL;

    if ( $(this.typeFieldId).value )
      url += '/' + encodeURI($(this.typeFieldId).value);
    else
      url += '/ALL';
    url += '/' + encodeURI($(this.searchFieldId).value);

    //+ means + not space. encodeURI does not agree.
    url = url.replace(/\+/g, '%2B');
    
    $(this.formId).action = url;
    return true;
  },

  changeType: function( type )
  {
    $(this.typeFieldId).value = type;
    this.submit();
    return false;
  },

  preview: function()
  {
    var query = $(this.searchFieldId).value;
    if (( this.previousQuery == null ) || ( query != this.previousQuery ))
    {
      if ( this.keyPressTimeout != null )
        clearTimeout( this.keyPressTimeout );

      this.keyPressTimeout = setTimeout( this.doPreview.bind(this), 200 );
    }
  },

  doPreview: function()
  {
    var query = $(this.searchFieldId).value
    if ( query )
    {
      var types = new Array();
      for ( var type in this.typeLinkMap )
        types.push( type );
      objectSearch.matchesForTypes( query, types, { callback: this.handlePreview.bind(this, query),
                                                errorHandler: this.clearPreview.bind(this) } );
    }
  },

  handlePreview: function( query, matchesMap )
  {
    // ignored if results don't represent current query
    if ( query != $(this.searchFieldId).value )
      return;

    var matches = '';
    for ( var type in matchesMap )
    {
      $(this.typeLinkMap[type][1]).innerHTML = matchesMap[type];
      if ( type == this.currentType )
        $(this.currentCountId).innerHTML = matchesMap[type];
    }
  },

  clearPreview: function( )
  {
    $(this.currentCountId).innerHTML = '&nbsp;';
    for ( var type in this.typeLinkMap )
      $(this.typeLinkMap[type][1]).innerHTML = '&nbsp;';
  }
}

var PulldownSearchController = Class.create();
PulldownSearchController.prototype = {
  resultsContainerId: null,
  searchInputId: null,
  resultTemplate: null,
  containerTemplate: null,
  resultsId: null,
  results: null,
  menuItemPrefix: null,
  selectedClass: null,
  selectedIndex: null,
  menuOpen: false,
  previousQuery: null,
  keyPressTimout: null,
  type: null,
  types: null,
  maxheight: null,
  actionHandler: null,
  overResults: false,

  initialize: function( actionHandler, searchInputId, resultsId, resultsContainerId,
                        menuItemPrefix, selectedClass, type, maxheight )
  {
    this.actionHandler = actionHandler;
    this.resultsContainerId = resultsContainerId;
    this.resultsId = resultsId;
    this.searchInputId = searchInputId;
    this.menuItemPrefix = menuItemPrefix;
    this.selectedClass = selectedClass;
    if (type.split(',').length > 1)
      this.types = 'type:' + type.split(',').join(' type:');
    else
      this.type = type;
    this.maxheight = maxheight;

    this.resultTemplate = new smilemaker.Template( $(resultsContainerId).innerHTML );

    this.containerTemplate = new smilemaker.Template( smilemaker.Template
              .cleanTemplate( $(resultsId).innerHTML
              .replace( $(resultsContainerId).innerHTML, '{data}' ) ) );
    $(resultsId).innerHTML = "";

    $(this.searchInputId).onkeyup = this.handleSearchKey.bindAsEventListener(this);
    $(this.searchInputId).onkeydown = this.handleMovementKey.bindAsEventListener(this);
    $(this.searchInputId).onblur = this.handleBlur.bind(this);
    $(this.resultsId).onmouseover = this.handleOverResults.bind(this);
    $(this.resultsId).onmouseout = this.handleOutResults.bind(this);
  },

  handleSearchKey: function( event )
  {
    var query = $(this.searchInputId).value;
    if (( this.previousQuery == null ) || ( query != this.previousQuery ))
    {
      if ( this.keyPressTimeout != null )
        clearTimeout( this.keyPressTimeout );

      if ( query.length > 0 )
      {
        this.keyPressTimeout = setTimeout( this.doSearch.bind(this, query), 200 );
        this.previousQuery = query;
      }
      else
      {
        this.previousQuery = null;
        this.closeMenu();
      }
    }
  },

  handleMovementKey: function( event )
  {
    switch ( event.keyCode )
    {
      case Event.KEY_DOWN:
        this.selectDown();
        return;

      case Event.KEY_UP:
        this.selectUp();
        return;

      case Event.KEY_ESC:
        this.closeMenu();
        return;

      case Event.KEY_RETURN:
        this.action();
        return;
    }
  },

  handleBlur: function( event )
  {
    if ( ! this.overResults )
      this.closeMenu();
  },

  handleOverResults: function()
  {
    this.overResults = true;
  },

  handleOutResults: function()
  {
    this.overResults = false;
  },

  handleFocus: function( event )
  {
    if ( ! Popup.isDescendant( event.target, $(this.resultsContainerId) ) )
      this.closeMenu();
  },

  doSearch: function()
  {
    var query = $(this.searchInputId).value
    if ( query )
    {
      var subQuery = query;
      if ( query.indexOf(':') < 0 )
        subQuery = 'label:(' + query + '*) body:(' + query + '*)';

      if (this.types != null)
        subQuery = '+(' + this.types + ') AND +(' + subQuery + ')';
      else
        subQuery = '+(type:' + this.type + ') AND +(' + subQuery + ')';
      $('spinner').show();
      objectSearch.search( subQuery, {  callback: this.handleSearch.bind(this, query),
                                    errorHandler: this.closeMenu.bind(this) } );
    }
  },

  action: function()
  {
    if (( this.actionHandler ) && ( this.results ))
    {
      this.actionHandler( this.results[this.selectedIndex] );
    }
    this.closeMenu();
  },

  handleSearch: function( query, results )
  {
    $('spinner').hide();
    // ignored if results don't represent current query
    if ( query != $(this.searchInputId).value )
      return;

    this.results = new Array();
    for ( var i=0; i < results.length; i++ )
      this.results.push( { index:i+'',
                           label:results[i].label,
                           referenceKey:results[i].referenceKey,
                           key:results[i].type + ':::' + results[i].identifier + ':::' + results[i].locale } );
    var rows = this.resultTemplate.evaluateMultiple(this.results);
    $(this.resultsId).innerHTML = this.containerTemplate.evaluate({data:rows});

    for ( var i=0; i < results.length; i++ )
    {
      var row = $( this.menuItemPrefix + i );
      row.onmouseover = this.select.bind( this, i );
      row.onclick = this.action.bind( this );
    }

    if ( this.results.length > 0 )
      this.openMenu();
    else
      this.closeMenu();

    this.overResults = false;
  },

  openMenu: function()
  {
    Popup.openUnder(this.resultsId, this.searchInputId, this.maxheight);
    Popup.hideSelects($(this.searchInputId).form, this.resultsId);
    this.menuOpen = true;
    this.select(0);
    Popup.keepVisibleInDocument( this.resultsId );
  },

  closeMenu: function()
  {
    this.menuOpen = false;
    Element.hide(this.resultsId);
    this.selectedIndex = null;
    Popup.restoreSelects($(this.searchInputId).form);
  },

  selectDown: function()
  {
    if (( ! this.menuOpen ) && ( this.results != null ))
      this.openMenu();

    var index = (this.selectedIndex != null ? this.selectedIndex + 1 : 0);
    if ( index >= this.results.length )
      index = 0;
    this.select( index );
  },

  selectUp: function()
  {
    if (( ! this.menuOpen ) && ( this.results != null ))
      this.openMenu();

    var index = (this.selectedIndex != null ? this.selectedIndex - 1 : this.results.length - 1);
    if ( index < 0 )
      index = this.results.length - 1;
    this.select( index );
  },

  keepSelectionVisible: function()
  {
    var element = $(this.selectedElement());
    var container = $(this.resultsId);
    var offset = this.offsetFromContainer(element, container);
    if ( offset + element.offsetHeight > container.offsetHeight + container.scrollTop )
      container.scrollTop = offset + element.offsetHeight - container.offsetHeight;
    if ( offset < container.scrollTop )
      container.scrollTop = offset;
  },

  offsetFromContainer: function( element, container )
  {
      var y = 0;
      while ((element.offsetParent) && ( element != container )) {
        y += element.offsetTop + (element.clientTop || 0);
        element = element.offsetParent;
      }
      return y;
  },

  selectedElement: function()
  {
    return $(this.menuItemPrefix + this.selectedIndex);
  },

  select: function( index )
  {
    if ( this.selectedIndex != null )
      Element.removeClassName(this.menuItemPrefix + this.selectedIndex, this.selectedClass);

    this.selectedIndex = index;
    Element.addClassName(this.menuItemPrefix + index, this.selectedClass);

    this.keepSelectionVisible();
  }

}

var ListEditController = Class.create();
ListEditController.prototype = {
  listEditorId : null,
  addTemplate     : null,
  numItems        : null,
  inlineContentURL : null,

  initialize: function( listEditorId, elementIdPrefixTemplate, inlineContentURL )
  {
    this.listEditorId = listEditorId;
    this.inlineContentURL = inlineContentURL;
    this.idPrefix = elementIdPrefixTemplate.join('');
    elementIdPrefixTemplate[1] = '!{index}';
    this.prefixReplacement = elementIdPrefixTemplate.join('');

    var listEditor = $(this.listEditorId);
    var templateString = listEditor.select('.js-add-template')[0].value;
    this.addTemplate = new Template(templateString.replace(new RegExp(this.idPrefix,"g"),this.prefixReplacement), /(^|.|\r|\n)(\!\{\s*(\w+)\s*\})/);
    var items = listEditor.select('.js-list-container .js-list-item');
    for ( var i=0,item; item = items[i]; i++ )
      this.wire(item);
    this.numItems = items.length;
    this.reconfigureItems();

    listEditor.select('.js-add-list-item-button')[0].observe('click', this.addItem.bind(this) );
  },

  addItem: function()
  {
    var container = $(this.listEditorId).select('.js-list-container')[0];
    var evaluated = this.addTemplate.evaluate(
        {
          index:this.numItems,
          displayIndex:this.numItems+1,
          endTextarea:'</textarea>'
        });
    container.insert({bottom:evaluated});
    this.wire( container.select('.js-list-item')[this.numItems] );
    this.reconfigureItems();
    this.numItems++;

    var listOps = $(this.listEditorId).select('.js-old-list-operations')[0];
    listOps.value = (listOps.value != null && listOps.value.length > 0 ? listOps.value+':' : '' ) + 'ADD';
  },

  addInlineContent: function(path,key,parentType,parentPath)
  {
    new Ajax.Request(this.inlineContentURL, {
        method: 'get',
        parameters: { path:path, key:key, parentType:parentType, parentPath:parentPath },
        onSuccess: this.addInlineContent_onSuccess.bind(this, key)
      });
  },

  addInlineContent_onSuccess : function( key, result )
  {
    var container = $(this.listEditorId).select('.js-list-container')[0];
    var template = new Template(result.responseText.replace(new RegExp(this.idPrefix,"g"),this.prefixReplacement),
                                /(^|.|\r|\n)(\!\{\s*(\w+)\s*\})/);
    container.insert( {bottom: template.evaluate(
        {
          index:this.numItems,
          displayIndex:this.numItems+1
        })} );
    var listItem = container.select('.js-list-item')[this.numItems];
    listItem.select('.js-inline-reference-type')[0].value = key.split(':::')[0];
    listItem.select('.js-inline-reference-identifier')[0].value = key.split(':::')[1]; 
    this.wire( listItem );
    this.reconfigureItems();
    this.numItems++;

    var listOps = $(this.listEditorId).select('.js-old-list-operations')[0];
    listOps.value = (listOps.value != null && listOps.value.length > 0 ? listOps.value+':' : '' ) + 'ADD';
  },

  wire: function(item)
  {
    item.select('.js-up-button')[0].observe('click', this.moveUp.bind(this,item) );
    item.select('.js-down-button')[0].observe('click', this.moveDown.bind(this,item) );
    item.select('.js-delete-button')[0].observe('click', this.deleteItem.bind(this,item) );
  },

  reconfigureItems : function()
  {
    var items = $(this.listEditorId).select('.js-list-container')[0].select('.js-list-item');
    for ( var i=0,item; item = items[i]; i++ )
    {
      item.removeClassName( i%2==0 ? 'even' : 'odd'  );
      item.addClassName(    i%2==0 ? 'odd'  : 'even' );
      if ( i == 0 )
        item.select('.js-up-button')[0].hide();
      else
        item.select('.js-up-button')[0].show();
      if ( i == items.length - 1 )
        item.select('.js-down-button')[0].hide();
      else
        item.select('.js-down-button')[0].show();
      item.select('.js-display-index')[0].innerHTML = (i+1);
    }
  },

  moveUp : function(item)
  {
    this.listOp( item, function(items,currentIndex)
      {
        if ( currentIndex < 1 )
          return null;

        items[currentIndex - 1].insert({before:items[currentIndex]});
        return 'MOVE-UP-' + currentIndex;
      });
  },

  moveDown : function(item)
  {
    this.listOp( item, function(items,currentIndex)
      {
        if ( currentIndex >= items.length - 1 )
          return null;

        items[currentIndex + 1].insert({after:items[currentIndex]});
        return 'MOVE-DOWN-' + currentIndex;
      });
  },

  deleteItem : function(item)
  {
    this.listOp( item, function(items,currentIndex)
      {
        items[currentIndex].hide();
        return 'DELETE-' + currentIndex;
      });
  },

  listOp : function( item, action )
  {
    var items = $(this.listEditorId).select('.js-list-container')[0].select('.js-list-item');
    var currentIndex = items.indexOf( item );

    var op = action( items, currentIndex );
    if ( op == null )
      return;

    var listOps = $(this.listEditorId).select('.js-new-list-operations')[0];
    listOps.value = (listOps.value != null && listOps.value.length != 0 ? listOps.value+':' : '' ) + op;

    this.reconfigureItems();
  }
}


var ResourceSelectController = Class.create();
ResourceSelectController.prototype = {
  widgetId: null,
  fileInput: null,
  fakeFileInput: null,
  selectFile: null,
  selectedIndex: null,
  
  initialize: function( widgetId )
  {
    this.widgetId = widgetId;
    this.fileInput = $(widgetId + ".file");
    this.fakeFileInput = $(widgetId + ".fake-text");
    this.selectFile = $(widgetId + ".referenceKey");
    this.selectedIndex = this.selectFile.selectedIndex;
    this.reset();

    var that = this;
    this.bindFileBrowserEvents(this.fileInput);
    this.selectFile.onchange = function() { that.selectionChanged(); }
    $(widgetId + ".clear").onclick = function() { that.reset(); }

    if (navigator.appName == "Netscape")
    {
      $(widgetId + ".browse").style.margin = "0px 0px 0px 5px";
      $(widgetId + ".clear").style.margin = "0px 0px 0px 5px";
    }
  },

  selectionChanged: function()
  {
    this.selectedIndex = this.selectFile.selectedIndex;
    this.reset();
  },

  browsed: function()
  {
    if (this.fileInput.value != "")
      this.fakeFileInput.value = this.fileInput.value;
    this.selectFile.options[0].selected = true;
  },

  reset: function()
  {
    if (this.fileInput.value != "")
    {
      var parent = this.fileInput.parentNode;
      var newFileInput = document.createElement("input");
      newFileInput.id = this.fileInput.id;
      newFileInput.name = this.fileInput.name;
      newFileInput.className = this.fileInput.className;
      newFileInput.type = "file";
      newFileInput.size = "1";
      this.bindFileBrowserEvents(newFileInput);

      parent.removeChild(this.fileInput);
      parent.appendChild(newFileInput);
      this.fileInput = newFileInput;
    }

    this.fakeFileInput.value = "Click Browse to choose a file.";
    this.selectFile.options[this.selectedIndex].selected = true;
  },

  bindFileBrowserEvents: function(input)
  {
    var that = this;
    input.onkeydown = function() { return false; }
    input.onkeyup = function() { return false; }
    input.onkeypress = function() { return false; }
    input.onchange = function() { that.browsed(); }
  }
}