// any field changes: update preview
// [done] date range checkbox changes: enable or disable date inputs
// [done] when category is checked uncheck "all categories" checkbox
// [done] when all categories is checked uncheck each category checkbox
// [done] when select organisation dropdown is changed, update and enable website dropdown
// [done] if the number of websites is more than 1 add "All" option to website dropdown
// [done] when save source button is pressed add the contents of partial "saved_box_content" with the content partner and website variables
// [done] when save source button is pressed uncheck all sources checkbox
// [done] when save button is pressed hide the collection form and show the add another button
// [done] when edit source button is pressed hide the add source options, show edit source options in the correct row and show save button
// [done] when the edit source save button is pressed update the row
// [done] when the delete source button is pressed remove the content partner row
// [done] when add another button is pressed show the add source options
// when the colour is changed it should update the preview image

/**
 * This class controls a pair of select dropdowns, one being a list of content providers and the other
 * a list of collections for that content provider.
 */
var ContentPartnerSelect = Class.create({
  initialize: function(contentPartnerSelect, collectionSelect) {
    this.contentPartnerSelect = contentPartnerSelect;
    this.collectionSelect = collectionSelect;

    if (contentPartnerSelect==undefined || contentPartnerSelect.select('option').length == 0)
      this.loadPartnersIn();
    else if (!ContentPartner.contentPartners)
      this.loadPartnersOut();
    
    this.contentPartnerSelect.observe('change', this.changeHandler.bindAsEventListener(this));

  },

  /**
   * Return the selected collection
   */
  getCollection: function() {
    return this.collectionSelect.getValue();
  },

  /**
   * Return the selected ContentPartner
   */
  getContentPartner: function() {
    return ContentPartner.contentPartners[this.contentPartnerSelect.selectedIndex];
  },

  /**
   * Set the selected collection
   * @param value string
   */
  setCollection: function(value) {
    var option = this.collectionSelect.select('option').detect(function(option) { return option.value == value });
    if(option) option.selected = true;
  },

  /**
   * Set the selected content parter
   * @param value string or ContentPartner
   */
  setContentPartner: function(value) {
    if(value['name']) value = value['name'];

    var option = this.contentPartnerSelect.select('option').detect(function(option) { return option.value == value });
    if(option) option.selected = true;
    
    this.changeHandler();
  },

  /**
   * This function is run when the content partner dropdown is changed
   * @param event
   */
  changeHandler: function(event) {
    var contentPartner = this.getContentPartner();
    this.contentPartnerSelect.disable();
    this.collectionSelect.disable();
    this.collectionSelect.update('<option>Loading websites...</option>');
    contentPartner.getCollections(this.populateCollections.bind(this));
  },

  /**
   * Populate the collection dropdown using the given array of string values. If there is
   * more than one value then an 'All' option will be added.
   * @param collections
   */
  populateCollections: function(collections) {
    this.collectionSelect.update(collections.map(function(collection) {
      return '<option value="' + collection + '">' + collection + '</option>';
    }));

    if (collections.length > 1) {
      this.collectionSelect.insert({top: '<option value="">All</option>'});
    }

    this.collectionSelect.enable();
    this.contentPartnerSelect.enable();
  },

  /**
   * This will populate the content partners dropdown from the ContentPartner.contentPartners variable
   */
  loadPartnersIn: function() {
    this.contentPartnerSelect.update('');
    ContentPartner.contentPartners.each(function(partner) {
      this.contentPartnerSelect.insert('<option value="' + partner.name + '">' + partner.name + '</option>');
    }.bind(this));
  },

  /**
   * This will use the contents of the dropdown to fill the ContentPartner.contentPartners variable
   */
  loadPartnersOut: function() {
    ContentPartner.contentPartners = this.contentPartnerSelect.select('option').pluck('value').map(function(name) {
      return new ContentPartner(name);
    });
  }
});

/**
 * This class represents a ContentPartner. It is created with a name, and provides methods for getting the collections.
 */
var ContentPartner = Class.create({
  initialize: function(partner) {
    this.contentPartner = partner;
    this.name = partner;
  },

  /**
   * Get the list of available collections. This function is asynchronous, so a function must be passed that
   * is called later with the array of collections.
   * @param fn
   */
  getCollections: function(fn) {
    if (this.collections) {
      fn(this.collections);
      return;
    }

    new Ajax.Request('/customise/populate_collections.json', {
      method: 'get',
      parameters: {content_partner: this.name},
      onSuccess: function(response) {
        this.populateCollections(response.responseJSON, fn);
      }.bind(this)
    });
  },

  /**
   * Private function for retrieving the collections
   * @param collections
   * @param fn
   */
  populateCollections: function(collections, fn) {
    this.collections = collections;
    fn(this.collections);
  }
});

/**
 * This class controls the users content partner selections
 */
var ContentPartnerRow = Class.create({
  initialize: function(partner, collection) {
    this.contentPartner = partner;
    this.collection = collection;
    this.name = partner.name;
    this.template = new Template(content_partner_template);
  },

  getFormatted: function() {
    var formatted = {
      name: this.name,
      displayName: this.name,
      collection: this.collection,
      displayCollection: this.collection,
      index: this.index,
      className: ((this.index % 2 == 0) ? 'odd' : 'even')
    };

    if (formatted.name.length > 27)
      formatted.displayName = formatted.name.substr(0, 25) + '...';
    if (formatted.collection!=undefined && formatted.collection.length > 27)
      formatted.displayCollection = formatted.collection.substr(0, 25) + '...';

    if (!formatted.collection || formatted.collection == '')
      formatted.displayCollection = 'All';

    return formatted;
  },

  /**
   * Create the content partner row element using the template
   * @param parent
   * @param index
   */
  createElement: function(parent, index) {
    this.index = index;
    var html = this.template.evaluate(this.getFormatted());
    $(parent).insert(html);
    this.element = $(parent).childElements().last();
    this.setupElement();
    return this.element;
  },

  /**
   * Set up the element by adding event listeners to the delete, edit and save buttons.
   */
  setupElement: function() {
    this.element.down('.delete').observe('click', this.deleteHandler.bindAsEventListener(this));
    this.element.down('.edit').observe('click', this.editHandler.bindAsEventListener(this));

    this.contentPartnerSelect = new ContentPartnerSelect(
            this.element.down('.content-partner-select'),
            this.element.down('.collection-select')
            );
    this.element.down('.save_button').observe('click', this.saveHandler.bindAsEventListener(this));
    // Set the content partner and collection in the edit dropdowns
    this.contentPartnerSelect.setContentPartner(this.name);
    this.contentPartnerSelect.setCollection(this.collection);
  },

  /**
   * This function is run when the delete button is clicked. It deletes the row.
   * @param event
   */
  deleteHandler: function(event) {
    event.stop();

    if (this.element)
      this.element.remove();

    if (this.onDelete && this.index)
      this.onDelete(index);
  },

  /**
   * This function is run when the edit button is clicked. It shows the dropdowns for editing the row.
   * @param event
   */
  editHandler: function(event) {
    event.stop();

    if (this.element) {
      this.element.select('.shown').invoke('hide');
      this.element.select('.hidden').invoke('show');
    }
  },

  /**
   * This function is run when the save button is clicked. It sets the data from the dropdowns and replaces the
   * current element with a new one showing the new data.
   * @param event
   */
  saveHandler: function(event) {
    event.stop();
    
    this.contentPartner = this.contentPartnerSelect.getContentPartner();
    this.name = this.contentPartner.name;
    this.collection = this.contentPartnerSelect.getCollection();

    var oldElement = this.element;
    var parent = $(oldElement.parentNode);

    this.createElement(parent, this.index);
    oldElement.replace(this.element);
    this.element.show();
  }
});

/**
 * This class controls the whole custom search form.
 */
var CustomSearchForm = Class.create({
  initialize: function(element) {
    this.element = $(element);

    this.setupDateFields();
    this.setupCategories();
    this.setupContentPartners();
    this.setupFormListener();
  },

  /**
   * Listen for changes to the form data and update the preview if it changes.
   */
  setupFormListener: function() {
    setTimeout(function() {
      var serializedForm = this.serialize();
      if (serializedForm != this.lastSerialization) {
        this.lastSerialization = serializedForm;
        this.updatePreview();
      } else {
        this.setupFormListener();
      }
    }.bind(this), 1000);
  },

  /**
   * Observe the date fields
   */
  setupDateFields: function() {
    this.allDateRadio = this.element.down('#date');
    this.specificDateRadio = this.element.down('#date-specific');

    [this.allDateRadio, this.specificDateRadio].invoke('observe', 'click', this.dateClickHandler.bindAsEventListener(this));
    this.dateClickHandler();
  },

  /**
   * When the date radio buttons are changed enable or disable the date input boxes
   * @param event
   */
  dateClickHandler: function(event) {
    $('custom_search_date_start', 'custom_search_date_end').invoke(this.allDateRadio.checked ? 'disable' : 'enable');
  },

  /**
   * Observe the category checkboxes
   */
  setupCategories: function() {
    this.categoryCheckboxes = $$('#custom_search_include input');
    this.categoryCheckboxes.invoke('observe', 'click', this.categoryClickHandler.bindAsEventListener(this));
  },

  /**
   * When a category is clicked, if it is the "all" category then other categories are unchecked. Otherwise
   * the all category is unchecked. This also prevents all from being unchecked by itself.
   * @param event
   */
  categoryClickHandler: function(event) {
    var clicked = event.element();
   
    if (clicked.checked && clicked.id == 'category-everything') {
      this.categoryCheckboxes.each(function(box) {
        box.checked = false;
      });
      clicked.checked = true;
    } else if (clicked.id == 'category-everything') {
      clicked.checked = true;
    } else {
      $('category-everything').checked = false;
    }
  },

  /**
   * Find and observe the content partner dropdowns
   */
  setupContentPartners: function() {
    // Create an array for storing the user selected rows
    this.contentPartnerRows = [];

    // The all sources checkbox
    this.allCollections = this.element.down('#inst-all');
    // The container of the dropdowns
    this.contentPartnerSelectionBox = this.element.down('#source_selectors');
    // The save button
    this.contentPartnerSaveButton = this.contentPartnerSelectionBox.down('.save_button');
    // The add another button
    this.addAnotherButton = this.element.down('#small_add_source_button');

    // Set up the dropdowns
    this.contentPartnerSelect = new ContentPartnerSelect(
            this.contentPartnerSelectionBox.down('.content-partner-select'),
            this.contentPartnerSelectionBox.down('.collection-select')
            );

    // Observe the save button
    this.contentPartnerSaveButton.observe('click', this.contentPartnerSaveHandler.bindAsEventListener(this));
    // Observe the add another button, using it to toggle the visibility of the dropdowns
    this.addAnotherButton.observe('click', function(event) {
      event.stop();
      this.toggleContentPartnerSelectionBox();
    }.bindAsEventListener(this));

    // Observe the all sources checkbox
    this.allCollections.observe('click', this.allCollectionsClickHandler.bindAsEventListener(this));

    // Load current selections
    this.loadCurrentContentPartnerRows();
  },

  /**
   * If the user is editing a current custom search then it may already have sources. This will
   * find them and pull them into the array. It will then remove them and re-render so that everything
   * is correctly setup.
   */
  loadCurrentContentPartnerRows: function() {
    $('sources').select('.saved_content_partner').each(function(element) {
      var partner = element.down('input.partner').getValue();
      var collection = element.down('input.collection').getValue();
      var contentPartner = ContentPartner.contentPartners.detect(function(cp) { return cp.name == partner; });
      this.addSource(contentPartner, collection);
    }.bind(this));

    this.renderContentPartnerRows();
  },

  /**
   * When the all sources checkbox is clicked this will confirm with the user then clear the current sources.
   * @param event
   */
  allCollectionsClickHandler: function(event) {
    if(this.contentPartnerRows.length > 0) {
      if(confirm('This will remove your current source selections. Do you want to continue?')) {
        this.contentPartnerRows = []
        this.renderContentPartnerRows();
      } else {
        event.stop();
      }
    }
  },

  /**
   * When the save button is clicked this will check a content partner has been selected then create
   * a new ContentPartnerRow and render it. It will also uncheck the all sources checkbox and hide
   * the content partner dropdowns.
   * @param event
   */
  contentPartnerSaveHandler: function(event) {
    event.stop();
   
    var contentPartner = this.contentPartnerSelect.getContentPartner();
    var collection = this.contentPartnerSelect.getCollection();

    if (!contentPartner || contentPartner.name == '') {
      this.errorMessage('You must choose a content partner before saving.');
      return;
    }

    this.allCollections.checked = false;
    this.toggleContentPartnerSelectionBox();
    
    var element = this.addSource(contentPartner, collection);
    Effect.Appear(element);
  },

  /**
   * Toggle the visiblity of the content partner and collection dropdowns.
   */
  toggleContentPartnerSelectionBox: function() {
    if (this.contentPartnerSelectionBox.visible()) {
      Effect.Fade(this.contentPartnerSelectionBox, {queue: 'front', duration: 0.2});
      Effect.Appear(this.addAnotherButton, {queue: 'end', duration: 0.2});
    } else {
      Effect.Fade(this.addAnotherButton, {queue: 'front', duration: 0.2});
      Effect.Appear(this.contentPartnerSelectionBox, {queue: 'end', duration: 0.2});
    }
  },

  /**
   * Add a source. This creates a ContentPartnerRow and returns it's element.
   * @param contentPartner a ContentPartner object
   * @param collection a collection string
   */
  addSource: function(contentPartner, collection) {
    var contentPartnerRow = new ContentPartnerRow(contentPartner, collection);
    // Set up the onDelete handler
    contentPartnerRow.onDelete = function(index) {
      this.contentPartnerRows.splice(index, 1);
      this.renderContentPartnerRows();
    }.bind(this);

    this.contentPartnerRows.push(contentPartnerRow);
    var index = this.contentPartnerRows.length - 1;
    return this.createContentPartnerRow(index);
  },

  /**
   * This loops through all available ContentPartnerRow objects,
   * creates their element and makes it visible.
   */
  renderContentPartnerRows: function() {
    var sources = $('sources');
    sources.update('');

    for (var i = 0; i < this.contentPartnerRows.length; i++) {
      var element = this.createContentPartnerRow(i);
      element.show();
    }
  },

  /**
   * Create the element for the ContentPartnerRow
   * @param index
   */
  createContentPartnerRow: function(index) {
    var contentPartner = this.contentPartnerRows[index];
    return contentPartner.createElement('sources', index);
  },

  /**
   * This serializes the form into a query string.
   */
  serialize: function() {
    return this.element.serialize(false);
  },

  /**
   * Update the preview
   */
  updatePreview: function() {
    new Ajax.Updater('search_preview', '/customise/preview', {
      method: 'get',
      parameters: this.serialize(),
      onComplete: this.setupFormListener.bind(this)
    });
  }
});

/**
 * Initialize the form and save it to CustomSearchForm.form
 */
CustomSearchForm.init = function() {
  if (CustomSearchForm.form) return CustomSearchForm.form;
  var form = $$('#content form')[0];
  if (form) CustomSearchForm.form = new CustomSearchForm(form);
  return CustomSearchForm.form;
};

/**
 * This function updates the search preview
 * @param key
 * @param title
 */
function update_search_preview(key, title) {
  $('custom_search_preview').src = "/images/site/screenshots/" + key + ".gif";
  $('custom_search_preview').alt = title + " hosted search preview";
}

document.observe('dom:loaded', CustomSearchForm.init);

//
//document.observe('dom:loaded', function() {
//  custom_search_init()
//});
//
//// var categories = ['category-images', 'category-audio', 'category-videos', 'category-researchpapers',
////    'category-interactives', 'category-webpages', 'category-journals',  'category-manuscripts'];
//// var category_everything = 'category-everything';
//
//function custom_search_init() {
//  setup_custom_search_toggles();
//}
//
//function setup_custom_search_toggles() {
//  //Set things to the right states
//  date_range_handler();
//  content_source_handler();
//
//  //observe the media type checkboxes
//  if ($('category-everything')) {
//    $('category-everything').observe('click', function(e) {
//      on_category_click(Event.element(e));
//    });
//  }
//  if ($('everything_else')) {
//    $('everything_else').select('input').each(function(cb) {
//      cb.observe('click', function(e) {
//        on_category_click(cb);
//      });
//    });
//  }
//
//
//  /*  set_collection_observer();*/
//  if ($('custom_search_keywords_input')) $('custom_search_keywords_input').observe('keyup', function(e) {
//    call_update_preview();
//  });
//  if ($('custom_search_date_start')) $('custom_search_date_start').observe('blur', function(e) {
//    call_update_preview();
//  });
//  if ($('custom_search_date_end')) $('custom_search_date_end').observe('blur', function(e) {
//    call_update_preview();
//  });
//  if ($('language-all')) $('language-all').observe('click', function(e) {
//    call_update_preview();
//  });
//  if ($('language-mi')) $('language-mi').observe('click', function(e) {
//    call_update_preview();
//  });
//  if ($('date')) $('date').observe('click', function(e) {
//    call_update_preview();
//  });
//  if ($('date-specific')) $('date-specific').observe('click', function(e) {
//    call_update_preview();
//  });
//
//  if ($('date')) $('date').observe('click', function() {
//    date_range_handler();
//  });
//  if ($('date-specific')) $('date-specific').observe('click', function() {
//    date_range_handler();
//  });
//
//  if ($('inst-all')) $('inst-all').observe('click', function() {
//    content_source_handler();
//  });
//}
///*
// function set_collection_observer() {
// if ($('collection')) { alert('cake'); $('collection').observe('change', function(e){ call_update_preview(); });}
// }*/
//function date_range_handler() {
//  if ($('date').checked) {
//    $('custom_search_date_start').disable()
//    $('custom_search_date_end').disable()
//  } else {
//    $('custom_search_date_start').enable()
//    $('custom_search_date_end').enable()
//  }
//}
//
//function content_source_handler() {
//  if ($('content_partner')) {
//    if ($('inst-all').checked) {
//      $('collection').disable();
//    } else {
//      $('content_partner').enable();
//
//      if ($F('content_partner') != '') {
//        $('collection').enable();
//      } else {
//        $('collection').disable();
//      }
//
//    }
//  }
//  call_update_preview();
//}
//function on_category_click(checkbox) {
//
//  if (checkbox.id == 'category-everything') {
//    $('everything_else').select('input').each(function(e) {
//      e.checked = false;
//    });
//  } else {
//    $('category-everything').checked = false;
//  }
//
//  call_update_preview();
//}
//
//function populate_collections(content_partner) {
//  if ($('collection') && $('collection').options) {
//    $('collection').options[0].text = 'Loading websites...';
//    $('collection').selectedIndex = 0;
//    $('collection').disabled = true;
//  }
//  new Ajax.Updater('collection_container', '/customise/populate_collections', {method: 'get', parameters: {content_partner:content_partner}});
//
//}
//function save_source(elem) {
//  var params = {};
//  params['number_of_saved'] = $('source_box').select('.saved_content_partner').length;
//  if ($F('content_partner') != '') {
//    if ($F('content_partner') != '') {
//      params['content_partner'] = $F('content_partner');
//      if ($F('collection') != '' && $F('collection') != '- Please select -') {
//        params['collection'] = $F('collection');
//      } else {
//        params['collection'] = 'All';
//      }
//    }
//
//    if (elem.parentNode.id == 'source_selectors') {
//      new Effect.Opacity('source_selectors', {from:1.0, to:0.3, duration:0.2});
//      new Ajax.Updater('sources', '/customise/source_save',
//      {method: 'get', parameters: params, insertion:Insertion.Bottom,
//        onComplete: function(transport) {
//          on_source_saved();
//        }
//      });
//      new Effect.Highlight($('source_selectors'))
//    } else {
//      params['edit'] = true;
//      params['number_of_saved'] = params['number_of_saved'] - 1;
//      new Ajax.Updater(elem.parentNode, '/customise/source_save',
//      {method: 'get', parameters: params,
//        onComplete: function(transport) {
//          Effect.Appear('small_add_source_button');
//        }
//      });
//    }
//  } else {
//    error_message('You must choose a content partner before saving.');
//  }
//}
//
//function on_source_saved() {
//  Effect.Fade('source_selectors', {queue:'front'});
//  Effect.Appear('small_add_source_button', {queue:'end'});
//  reset_source_selectors();
//}
//
//function edit_source(elem) {
//  var params = {};
//  if ($('sources').select('#content_partner') == 0) {
//    Effect.Fade('small_add_source_button');
//    Effect.Fade('source_selectors');
//    Element.up(elem).childElements().each(function(child) {
//      //elem.parentNode.childElements().each (function(child) {
//      if (child.name == 'content_partner[][0]') {
//        params['content_partner'] = child.value;
//      }
//      if (child.name == 'content_partner[][1]') {
//        params['collection'] = child.value;
//      }
//    });
//    new Effect.Opacity('sources', {from:1.0, to:0.3, duration:0.2});
//    new Ajax.Updater(elem.parentNode, '/customise/source_selectors',
//    {
//      parameters: params,
//      onComplete: function(transport) {
//        new Effect.Opacity('sources', {from:0.3, to:1.0, duration:0.2});
//      }
//    });
//  } else {
//    error_message('You may only edit one source at a time.');
//  }
//}
//
//function error_message(message) {
//  alert(message);
//}
//
//function delete_source(elem) {
//
//  Element.remove(elem.parentNode);
//  var rowc = 0;
//  $('sources').select('.saved_content_partner').each(function(el) {
//    var name = 'saved_content_partner';
//    rowc % 2 == 0 ? name += ' odd' : name += ' even';
//    el.className = name;
//    rowc++;
//  });
//  update_preview();
//  if ($('sources').select('.saved_content_partner').length == 0) {
//    add_source();
//  }
//
//}
//
//function add_source() {
//  Effect.Fade('small_add_source_button');
//  $('content_partner').disabled = false;
//  Effect.Appear('source_selectors');
//}
//
//function on_content_partner_change(elem) {
//  if ($('content_partner').selectedIndex == 0) {
//    $('inst-all').checked = true;
//    call_update_preview();
//  } else {
//    $('inst-all').checked = false;
//    populate_collections($('content_partner').options[$('content_partner').selectedIndex].value);
//    call_update_preview();
//  }
//
//}
//
//function reset_source_selectors() {
//
//  if ($('content_partner')) {
//    $('content_partner').selectedIndex = 0;
//  }
//  if ($('collection')) {
//    $('collection').selectedIndex = 0;
//    $('collection').options[0].text = "";
//    $('collection').disabled = true;
//  }
//
//}
//
//var update_timeout;
//
//function call_update_preview() {
//  window.clearTimeout(update_timeout);
//  update_timeout = window.setTimeout('update_preview()', 500);
//}
//
////update the preview field with new search results
//function update_preview() {
//  new Ajax.Updater('search_preview', '/customise/preview', {
//    method: 'get',
//    parameters: $('content').down('form').serialize()
//  });
//}
//

