/*--------------------------------------------------------*/
/* Misc helpers                                           */                                
/*--------------------------------------------------------*/

Effect.DefaultOptions.duration = 0.2;

Element.PSMethods = {
  visible: function(element) {
    return ($(element).style.display != 'none');
  },
  disable: function(element) {
    $(element).disabled = true;
  },
  enable: function(element) {
    $(element).disabled = false;
  },
  empty: function(element) {
    return ($(element).innerHTML.match(/^\s*$/));
  },
  toggleActive: function(element) {
    element = $(element);
    if (element.active()) {
      element.deactivate();
    } else {
      element.activate();
    }    
    return element;
  },
  active: function(element) {
    return element['ps:active'];
  },
  activate: function(element) {
    element = $(element)
    if (element.active()) return element;
    element['ps:inactive_text'] = element.innerHTML;
    element['ps:inactive_class'] = element.className;
    element.innerHTML = element.getAttribute('ps:active_text');
    element.className = element.getAttribute('ps:active_class');
    element['ps:active'] = true;
    return element;
  },
  deactivate: function(element) {
    element = $(element)
    if (!element.active()) return element;
    element.innerHTML = element['ps:inactive_text'];
    element.className = element['ps:inactive_class'];
    element['ps:active'] = false;
    return element;
  },
  showTooltip: function(element) {
    element.tooltip = document.createElement("div");
    element.tooltip.addClassName('tooltip');
    if (!element.tooltip_text) element.tooltip_text = element.getAttribute('title')
    element.tooltip.innerHTML = element.tooltip_text;
    element.title = element.alt = '';
    element.parentNode.appendChild(element.tooltip);    
    Event.observe(element, 'mouseout', function() { Element.remove(element.tooltip); });
  }
}

Object.extend(Element, Element.PSMethods);
Object.extend(Element.Methods, Element.PSMethods);

Element.addMethods();


Object.extend(String.prototype, {
  toTitleCase: function() {
    var strOut = "";
    var exp = /(\b\w)(\S+\s*)/g;
    while ((match = exp.exec(this)) != null) {
      strOut += match[1].toUpperCase() + match[2].toLowerCase();
    }
    return strOut;
  }
})

var PS = {
  failure: function(id) {
    if (busy = $(id + '_spinner')) busy.hide();
    if (submit = $(id + '_submit')) submit.show();
    alert('We are sorry. There was an error communicating with server. We have been notified and will take a look shortly.');
  },
  loading: function(id) {
    if (busy = $(id + '_spinner')) busy.show();
    if (submit = $(id + '_submit')) submit.hide();
  }
}


/*--------------------------------------------------------*/
/* Auto-completer for finite set of items                 */                                
/*--------------------------------------------------------*/

// Based on Ajax.Autocompleter by Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Adapted by Lars Pind (http://www.pinds.com)

Ajax.SearchableSelect = Class.create();
Ajax.SearchableSelect.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(element, select, url, options) {
    this.element      = $(element);
    this.select       = $(select);
    this.has_focus    = false;
    this.changed      = false;
    this.url          = url;
    this.lastValue    = this.element.value;
    
    this.setOptions(options);
    this.options.asynchronous = true;
    this.options.onComplete   = this.onComplete.bind(this);
    this.options.frequency    = this.options.frequency || 0.4;
    
    if (this.options.indicator)
      this.indicator = $(this.options.indicator);
    
    this.observer = null;
    this.request = null;
    
    Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this));
    Event.observe(this.element, "focus", this.onFocus.bindAsEventListener(this));
    Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this));
  },
  
  startIndicator: function() {
    if (this.indicator) Element.show(this.indicator);
  },

  stopIndicator: function() {
    if (this.indicator) Element.hide(this.indicator);
  },
  
  onObserverEvent: function() {
    if (this.element.value != this.lastValue) {
      this.lastValue = this.element.value;  
      this.changed = false;
      this.startIndicator();
      this.options.parameters = this.options.callback ?
        this.options.callback(this.element, $F(this.element)) :
        Form.Element.serialize(this.element);
      this.request = (new Ajax.Request(this.url, this.options)).transport;
    }
  },
  
  onComplete: function(request) {
    if (!this.changed && request == this.request) {
      setTimeout((function() {
          eval(request.responseText);
          this.select.selectedIndex = 0;
      }).bind(this), 10);
      this.stopIndicator();
    }
  },
  
  onKeyPress: function(event) {
    switch(event.keyCode) {
      case Event.KEY_RETURN:
        if (this.options.onReturn) {
          Event.stop(event);
          if (this.select.selectedIndex >= 0) this.options.onReturn();
        }
        return;
      case Event.KEY_ESC:
        if (this.options.onEsc) {
          Event.stop(event);
          this.options.onEsc();
        }
        return;
      case Event.KEY_TAB:
      case Event.KEY_LEFT:
      case Event.KEY_RIGHT:
        return;
      case Event.KEY_UP:
        this.mark_previous();
        if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
        return;
      case Event.KEY_DOWN:
        this.mark_next();
        if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event);
        return;
    }
    this.changed = true;
    this.has_focus = true;
  
    if (this.observer)
      clearTimeout(this.observer);
    this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency * 1000);
  },
  
  onBlur: function() {
    this.has_focus = false;
  },

  onFocus: function() {
    this.has_focus = true;
  },

  mark_previous: function() {
    if (this.select.selectedIndex > 0) this.select.selectedIndex--
      else this.select.selectedIndex = this.select.length - 1;
  },

  mark_next: function() {
    if (this.select.selectedIndex < this.select.length-1) this.select.selectedIndex++
      else this.select.selectedIndex = 0;
  }
});


Object.extend(Element, {
  setClassName: function(element, className, add) {
    if (add)
      Element.addClassName(element, className)
    else
      Element.removeClassName(element, className);
  }
});


/*--------------------------------------------------------*/
/* Hovering with gradient background, eg. authors widget  */
/*--------------------------------------------------------*/

var Hover = {
  begin: function(element) {
    element = $(element);
    //element.style.background = 'url(/images/bg_editable_hover_sidebar.gif) repeat-y';
    element.addClassName('hover');
  },
  end: function(element) {
    element = $(element);
    //element.style.background = 'transparent';
    element.removeClassName('hover');
  }
}

/*--------------------------------------------------------*/
/* The edit link for the story editor                     */
/*--------------------------------------------------------*/

var Editable = {
  hover: {
    timer  : null,
    command: null,
    delay  : 750,
    clear: function() {
      if (!this.timer) return;
      clearTimeout(this.timer);
      eval(this.command);
      this.timer = this.command = null;
    },
    begin: function(element) {      
      this.clear();
      element = $(element);
      Hover.begin(element);
      $(element.id + '_tools').show();
    },
    end: function(element) {
      this.command = 'Editable.hover.hide("' + $(element).id +'")';
      this.timer = setTimeout(this.command, this.delay);
    },
    hide: function(element) {
      element = $(element);
      Hover.end(element);
      $(element.id + '_tools').hide();
    }
  }
}

/*--------------------------------------------------------*/
/* SectionForm                                            */
/*--------------------------------------------------------*/

var SectionForm = {
  toggle: function(link, element, focus) {
    element = $(element);
    $(link).toggleActive();
    Effect.toggle(element, 'blind', { afterFinish: function() { if (focus && element.visible()) $(focus).focus(); } });
  }
}  

/*--------------------------------------------------------*/
/* Story editor                                           */
/*--------------------------------------------------------*/

var ContentEdit = {
  onResize: function() {
    $('content_body').style.height = (window.innerHeight - 260) + 'px'; 
  },
  assets: {
    COUNT: 1,
    addRow: function(row) {
      this.COUNT += 1; 
      new Insertion.Bottom('upload_asset_rows', row.gsub(/__INDEX__/, this.COUNT));
      $('upload_asset_row_' + this.COUNT).hide();
      new Effect.BlindDown('upload_asset_row_' + this.COUNT);
    }
  },
  create: function(type, element) {
    var title = prompt('Title (you can always change this later)')
    if (!title) return false;
    var f = document.createElement('form'); 
    element.parentNode.appendChild(f); 
    f.method = 'POST'; 
    f.action = '/admin/contents/new'; 
    var e = document.createElement('input'); 
    e.name = 'content[title]'; 
    e.type = 'hidden';
    e.value = title; 
    f.appendChild(e); 
    var e = document.createElement('input'); 
    e.name = 'type'; 
    e.type = 'hidden';
    e.value = type; 
    f.appendChild(e); 
    f.submit();
  }
}

var Alertable = {
  onClick: function(element) {
    if (element.id == 'alert_all') {
      this.checkboxes().each(element.checked ? this.check : this.uncheck); 
    } else {      
      $('alert_all').checked = this.checkboxes().all(this.checked);
    }
  },
  checkboxes: function() {
    return $A(document.getElementsByClassName('alert_user', $('alerts')));
  },
  check: function(element) {
    element.checked = true;
  },
  uncheck: function(element) {
    element.checked = false;
  },
  checked: function(element) {
    return element.checked;
  },
  unchecked: function(element) {
    return !element.checked;
  }
}

var Author = {
  add: {
    onReturn: function(event) {
      alert('Author.add.onReturn');
      if (event.keyCode == Event.KEY_RETURN) {
        Event.stop(event);
        if ($('author_select').selectedIndex >= 0) $('author_add_form').onsubmit();
      }
    }      
  }
}

/*--------------------------------------------------------*/
/* HideRestore manager                                    */
/*--------------------------------------------------------*/

var HideRestoreManager = {
  saved: null,
  running: false,
  show: function(element, focus) {
    if (this.running) return
    this.running = true
    if (Element.visible(element)) return
    if (!this.saved) this.saved = document.createElement('div')
    Element.update(this.saved, $(element).innerHTML)
    new Effect.BlindDown(element, {
      duration: 0.2,
      manager: this,
      afterFinish: function(effect) {
        effect.options.manager.running = false;
        if (focus) $(focus).focus();
      }
    })
  },
  hide: function(element) {
    if (this.running) return
    this.running = true
    if (!Element.visible(element)) return
    if (Element.visible(element)) {
      new Effect.BlindUp(element, {
        duration: 0.2,
        manager: this,
        afterFinish: function(effect) {
          Element.update(effect.element, effect.options.manager.saved.innerHTML)
          effect.options.manager.running = false
        }
      })
    }
  },
  toggle: function(element, focus) {
    Element.visible(element) ? this.hide(element) : this.show(element, focus)
  }
}


/*--------------------------------------------------------*/
/* List with basket                                       */
/*--------------------------------------------------------*/

Effect.MoveSplitter = Class.create();
Effect.MoveSplitter.prototype = Object.extend(new Effect.Base(), {
  initialize: function(element) {
    this.element = $(element);
    this.element._overflow = this.element.style.overflow || 'visible';
    this.element.style.overflow = 'hidden';
    Element.show(this.element);

    var options = Object.extend({
      from:         0,
      threshold:    0,
      to:           25,
      shrink_from:  100,
      duration:     0.4,
      beforeStart:  function(effect) { 
        effect.element.style.width = effect.options.from + '%';
        $(effect.options.shrink_element).style.width = (effect.options.shrink_from - effect.options.from) + '%';
      },
      afterFinish:  function(effect) { 
        if (effect.options.to == 0) {
          Element.hide(effect.element);
          $(effect.options.shrink_element).style.width = (effect.options.shrink_from - effect.options.to) + '%';
        }
        effect.element.style.overflow = effect.element._overflow;
      }
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    this.setWidth(position);
  }, 
  setWidth: function(width) {
    this.element.style.width = width + '%';
    $(this.options.shrink_element).style.width = (this.options.shrink_from - width) + '%';
  }
});

var Basket = {
  visibleIds: [],
  selectedCount: 0,
  type: '',
  show: function() {
    if (this.visible()) return;
    new Ajax.Request('/admin/dashboard/basket_toggle?type=' + this.type + '&show=1', {asynchronous:true});
    $('left').className = 'Left';
    new Effect.MoveSplitter(
      'selected_container', 
      {
        shrink_element: 'left',
        from:           0,
        to:             25,
        afterFinish:    function(effect) { 
          $('show_selected_link').activate();
          effect.element.style.overflow = effect.element._overflow;
        }
      }
    );
  },
  hide: function() {
    if (!this.visible()) return;
    new Ajax.Request('/admin/dashboard/basket_toggle?type=' + this.type + '&show=0', {asynchronous:true});
    new Effect.MoveSplitter(
      'selected_container', 
      {
        shrink_element: 'left', 
        from:           25, 
        to:             0,
        afterFinish:    function(effect) { 
          effect.element.hide();
          $('left').style.width = '100%';
          $('left').className = 'Full';
          $('show_selected_link').deactivate();
          effect.element.style.overflow = effect.element._overflow;
        }
      }
    );
  },
  visible: function() {
    return $('selected_container').visible();
  },
  toggle: function() {
    if (this.visible()) this.hide(); else this.show();
  },
  submit: function() {
    new Ajax.Request(
      '/admin/dashboard/save_selection', {
        asynchronous:true, 
        evalScripts:true,
        onLoading:function(request){Element.show('selected_busy')},
        onComplete:function(request){Element.hide('selected_busy')},
        parameters:Form.serialize('check_box_form')
      }
    );
  },
  unselectOne: function(id) {
    for (var i = 0; i < this.visibleIds.length; i++) {
      if (this.visibleIds[i] == id) {
        row_box = $('check_row_' + this.visibleIds[i]);
        if (row_box.checked) {
          row_box.checked = false;
          Element.removeClassName('row_' + this.visibleIds[i], "checked");
        }
      }
    }
    new Ajax.Request(
      '/admin/dashboard/unselect?type=' + this.type, {
        asynchronous:true, 
        evalScripts:true,
        onLoading:function(request){Element.show('selected_busy')},
        onComplete:function(request){Element.hide('selected_busy')},
        parameters:"id="+encodeURIComponent(id)
      }
    );    
  },
  unselectAll: function() {
    $('check_all').checked = false;
    for (var i = 0; i < this.visibleIds.length; i++) {
      row_box = $('check_row_' + this.visibleIds[i]);
      if (row_box.checked) {
        row_box.checked = false;
        Element.removeClassName('row_' + this.visibleIds[i], "checked");
      }
    }
  },
  showIfEmpty: function() {
    if (this.selectedCount == 0) Basket.show();
  },
  onRowBoxClicked: function(check_box, id) {
    Element.setClassName('row_' + id, "checked", check_box.checked);
    Basket.submit();
    if (check_box.checked) Basket.showIfEmpty();
  },
  onHeaderBoxClicked: function(check_box) {
    for (var i = 0; i < this.visibleIds.length; i++) {
      row_box = $('check_row_' + this.visibleIds[i]);
      if (row_box.checked != check_box.checked) {
        row_box.checked = check_box.checked;
        Element.setClassName('row_' + this.visibleIds[i], "checked", check_box.checked);
      }
    }
    Basket.submit();
    if (check_box.checked) Basket.showIfEmpty();
  },
  onRowClicked: function(event) {
    if (Event.element(event).tagName != 'TD') return;
    id = this.id.split('_')[1];
    check_box = $('check_row_' + id);
    check_box.checked = !check_box.checked;
    Element.setClassName(this, "checked", check_box.checked);
    Basket.submit();
    if (check_box.checked) Basket.showIfEmpty();
  },
  submitBulkAction: function(action, container) {
    $('bulk_action').value = action; 
    Form.getElements(container).each(function(element) { 
      var input = document.createElement('input'); 
      input.name = element.name; 
      input.type = 'hidden'; 
      input.value = $F(element); 
      $('check_box_form').appendChild(input) 
    });
    $('check_box_form').submit();
  },
  submitFilter: function(filter, value) {
    $('bulk_action').value = action; 
    
    Form.getElements(container).each(function(element) { 
      var input = document.createElement('input'); 
      input.name = element.name; 
      input.type = 'hidden'; 
      input.value = $F(element); 
      $('check_box_form').appendChild(input) 
    });
    $('check_box_form').submit();
  }
  
}

/*--------------------------------------------------------*/
/* Theme editor                                           */
/*--------------------------------------------------------*/

var ThemeEditor = {
  onResize: function() {
    $('element_attachment_data').style.height = (window.innerHeight - 220) + 'px'; 
  },
  createCopy: function(source_theme_id, element) {
    var name = prompt('Name your new theme:')
    if (!name) return false;
    var f = document.createElement('form'); 
    element.parentNode.appendChild(f); 
    f.method = 'POST'; 
    f.action = '/admin/theme/copy/' + source_theme_id; 
    var e = document.createElement('input'); 
    e.name = 'name'; 
    e.value = name; 
    e.type = 'hidden';
    f.appendChild(e); 
    f.submit();
  },
  elementCreate: {
    toggle: function(link, element) {
      if (!$(element).visible() && $('element_attachment_data')['ps:dirty']) {
        if (confirm("You have unsaved changes to the file you're editing. Save changes now?")) {
          $('element_form').submit();
          return;
        }
      }
      SectionForm.toggle(link, element);
    },
    onSubmit: function(id, existing_names, prefix, suffix) {
      var name = $(id + '_name').value;
      if (!name.match(/^\s*[a-zA-Z][-_a-zA-Z0-9]*\s*$/)) { 
        alert("Please enter a valid name. Valid names consist of letters a-z, A-Z, 0-9, hyphen and underscore, " + 
              "and must start with a letter.");
        $(id + '_name').focus(); 
        return false;
      } else if (existing_names.include(prefix + name + suffix)) {
        alert("This filename has already been taken.");
        $(id + '_name').focus(); 
        return false;
      } else {
        $(id + '_submit').disabled = 'true'; 
        $(id + '_spinner').show();
        return true;
      }
    }
  }  
}


/*--------------------------------------------------------*/
/* Modified in-place-editor                               */
/*--------------------------------------------------------*/

/* InPlaceEditor which uses an AJAX update request to construct the form */

Ajax.InPlaceUpdateEditor = Class.create();
Object.extend(Ajax.InPlaceUpdateEditor.prototype, Ajax.InPlaceEditor.prototype);
Object.extend(Ajax.InPlaceUpdateEditor.prototype, {
  createEditField: function() {
    this.editField = document.createElement("span");
    this.form.appendChild(this.editField);
    $(this.form).hide();

    this.spinner = document.createElement("img");
    this.spinner.src = '/images/spinner.gif';
    this.element.parentNode.insertBefore(this.spinner, this.element);

    new Ajax.Updater(
      { success: this.editField, failure: null },
      this.options.get_form_url, {
        onComplete: this.onLoadedExternalForm.bind(this)
      });
  },
  onLoadedExternalForm: function() {
    this.element.parentNode.removeChild(this.spinner);
    this.spinner = null;
    $(this.form).show();
  }
});


/*--------------------------------------------------------*/
/* Register Form                                          */
/*--------------------------------------------------------*/

var RegisterForm = {
  MESSAGE: { 'blank':              '',
             'too_short':          'This is too short',
             'available_username': 'Terrific choice!',
             'available_email':    'Looking good!',
             'taken':              'Nope, this is taken',
             'invalid_email':      'Not a valid email',
             'does_not_match':     'Don\'t match',
             'ok':                 'Excellent choice!' },
  CLASS:   { 'blank':              'feedback ',
             'too_short':          'feedback error',
             'available_username': 'feedback ok',
             'available_email':    'feedback ok',
             'taken':              'feedback error',
             'invalid_email':      'feedback error',
             'does_not_match':     'feedback error',
             'ok':                 'feedback ok' },
  observeField: function() {
    for (var i = 0; i < arguments.length; i++) {
      Event.observe(this.field(arguments[i]), "change", new Function("RegisterForm.checkField('" + arguments[i] + "')"));
      RegisterForm.checkField(arguments[i]);
    }
  },
  field: function(fieldName) {
    return $('user_' + fieldName);
  },
  handleResponse: function(result, fieldName, value) {
    var element = $('user_' + fieldName + '_feedback');
    if (!element) return;
    element.innerHTML = RegisterForm.MESSAGE[result] || '';
    element.className = RegisterForm.CLASS[result] || '';
  },
  checkField: function(fieldName, handler) {
    var handler = handler || this.handleResponse;
    var field = this.field(fieldName);
    handler('blank', fieldName, field.value);
    if (field.value != "") {
      this[('check-' + fieldName.gsub(/_/, '-')).camelize()](handler);
    }
  },
  checkUsername: function(handler) {
    var value = this.field('username').value.replace(/[^\w]/g, "").toLowerCase();
    this.field('username').value = value;
    if (value.length < 4) {
      handler('too_short', 'username', value);
    } else {
      new Ajax.Request('/account/check_username?value=' + encodeURIComponent(value), { onComplete: function(transport, object) {
        handler(transport.responseText, 'username', value);
      }})
    }
  },
  checkEmail: function(handler) {
    var value = this.field('email').value;      
    if (!value.match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/)) {
      handler('invalid_email', 'email', value);
    } else {
      new Ajax.Request('/account/check_email?value=' + encodeURIComponent(value), { onComplete: function(transport, object) {
        handler(transport.responseText, 'email', value);
      }})
    }
  },
  checkPassword: function(handler) {
    this.checkPasswordConfirmation(handler);
  },
  checkPasswordConfirmation: function(handler) {
    var password = this.field('password').value;
    var confirmation = this.field('password_confirmation').value;
    if (password == '' || confirmation == '') return;
    handler(password == confirmation ? 'ok' : 'does_not_match', 'password_confirmation', confirmation);
  }
}




var LoginForm = {
  MESSAGE: { 'found':          'Found',
             'not_found':      'Not found' },
  CLASS:   { 'found':          'feedback ok',
             'not_found':      'feedback error' },
  observeField: function() {
    for (var i = 0; i < arguments.length; i++) {
      Event.observe(this.field(arguments[i]), "change", new Function("LoginForm.checkField('" + arguments[i] + "')"));
      LoginForm.checkField(arguments[i]);
    }
  },
  field: function(fieldName) {
    return $('login_' + fieldName);
  },
  handleResponse: function(result, fieldName, value) {
    var element = $('login_' + fieldName + '_feedback');
    if (!element) return;
    element.innerHTML = LoginForm.MESSAGE[result] || '';
    element.className = LoginForm.CLASS[result] || '';
  },
  checkField: function(fieldName, handler) {
    var handler = handler || this.handleResponse;
    var field = this.field(fieldName);
    handler('blank', fieldName, field.value);
    if (field.value != "") {
      this[('check-' + fieldName.gsub(/_/, '-')).camelize()](handler);
    }
  },
  checkUsername: function(handler) {
    var value = this.field('username').value;
    if (value.length > 0) {
      new Ajax.Request('/account/check_username_or_email?value=' + encodeURIComponent(value), { onComplete: function(transport, object) {
        handler(transport.responseText, 'username', value);
      }})
    }
  }
}
