// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults

// Utility functions
var Util = {};

Util.interstitial = function(text) {
  text = text || "Please wait";
  return new Element('div', {'class': 'interstitial'}).update(text + '...');
};

// POST to a URL. Not XHR; causes a page transition.
Util.post = function(action, method) {
  var f = new Element('form', {'method': 'POST', 'action': action});
  f.style.display = 'none';
  document.body.appendChild(f);
  if(method) {
    var m = new Element('input', {'type': 'hidden', 'name': '_method', 'value': method});
    f.appendChild(m);
  }
  f.submit();
};

Util.markUpErrors = function(formName, errors, summaryEl) {
  summaryEl = $(summaryEl);

  if(typeof(errors) != "object") {
    if(typeof(errors) == "string" && errors.isJSON()) {
      errors = errors.evalJSON();
    } else { 
      alert("We're sorry, an unexpected error occurred.");
      return;
    }
  }

  var unmarkableErrors = []

  errors.each(function(e) {
    var el = $(formName + "_" + e[0]);
    if(el == null) el = $(e[0]);
    if(el == null) { unmarkableErrors.push(e); return; }
    // highlight the element itself
    el.addClassName("erroneous");
    // build a cool error bubble
    el.insert({ before: 
		'<div class="formError">' +
		'  <div class="formErrorClosed"></div>' +
		'  <div class="formErrorOpen" style="display: none;">' +
		'    <div class="formErrorOpenBottom">' + e[1] + '</div>' +
		'    <div class="formErrorOpenBg"></div>' +
		'  </div>' +
		'</div>'
	      });
    // find what we just did
    var errEl = $(el.parentNode).down(".formError");
    // focus field when clicking on the closed indicator
    errEl.down(".formErrorClosed").observe("click", function() { el.focus(); });
    // instrument form field to show bubble when focused
    el.observe('focus', function() {
      if(!errEl.errorGone) { // Be resilient if error element goes away due to form resubmit
	errEl.style.zIndex = "5000"; // appear above other errors!
	errEl.down(".formErrorOpen").show();
	errEl.down(".formErrorClosed").hide();
      }
    });
    
    el.observe('blur', function() {
      if(!errEl.errorGone) {
	errEl.style.zIndex = "";
	errEl.down(".formErrorOpen").hide();
	errEl.down(".formErrorClosed").show();
      }
    });
  });

  // Populate summary element
  //var etext = errors.length + " errors";
  var etext = "errors";
  if(unmarkableErrors.length > 0) {
    if(errors.length == 1)
      summaryEl.update('<strong>An error occurred:</strong>');
    else
      summaryEl.update('<strong>We found ' + etext + ', including the following:</strong>');

    var listEl = new Element('ul');
    unmarkableErrors.each(function(e) {
      var english_field = e[0].replace('_', ' ');
      if (e[0] == 'base')
        listEl.appendChild(new Element('li').update(e[1])); // only display the msg
      else
        listEl.appendChild(new Element('li').update(english_field + ": " + e[1])); // display it "as is"
    });
    summaryEl.appendChild(listEl);
  } else {
    if(errors.length == 1) etext = "error";
    summaryEl.update('<strong>Please correct the ' + etext + ' we found below, and try again.</strong>');
  }
  summaryEl.show();
};

Util.clearMarkedUpErrors = function(formName, summaryEl) {
  if(summaryEl) { $(summaryEl).hide(); }
  // TODO this will inadvertently clear other forms' errors
  $$('.formError').each(function(e) { e.remove(); e.errorGone = true; });
  $$('.erroneous').each(function(e) { e.removeClassName('erroneous'); });
};

Util.displayErrors = function(response, targetEl) {
  targetEl = $(targetEl);
  if(response.isJSON()) {
    var errors = response.evalJSON();
    targetEl.update('<strong>Please fix the following problems and try again:</strong>');
    var listEl = new Element('ul');
    errors.each(function(e) {
      var english_field = e[0].replace('_', ' ');
      /* if (f = $(e[0])) {
        listEl.appendChild(new Element('li').update(e[1])); // only display the msg
      } else if (f = $(e[0])) {
        listEl.appendChild(new Element('li').update(e[1])); // only display the msg
        new Effect.Highlight(f, {restorecolor: '#ffff99'});
        f.focus();
      } else {
      } */
      if (e[0] == 'base') {
        listEl.appendChild(new Element('li').update(e[1])); // only display the msg
      } else {
        listEl.appendChild(new Element('li').update(english_field + ": " + e[1])); // display it "as is"
      }
      // had to add in :base field management. we can discuss if it seems weird -rob
      //
      // Doing a little surgery on Grisha's cool field highlighting until the
      // implementation is complete enough for production. -js
    });
    targetEl.appendChild(listEl);
  } else {
    targetEl.update('An error occurred while processing your request.');
  }
  targetEl.show();
  //new Effect.Highlight(targetEl);
};

Util.assureElementCenteredInIE = function(element) {
  if(Prototype.Browser.IE) {
    var marg = (document.body.offsetWidth / 2.0) - (element.offsetWidth / 2.0);
    element.style.marginLeft = marg + "px";
    var border = parseInt(element.currentStyle['borderWidth']);
    var height = document.documentElement.clientHeight -
      ((element.offsetTop + border) * 2);
    element.style.height = height + "px";
  }
};

Util.isWindows = function() {
  return navigator.platform.startsWith("Win");
};

Util.isIE6 = function() {
  // alert("OMG get a real browser!"); LOL, JK, sort of
  return navigator.userAgent.toLowerCase().indexOf('msie 6') != -1;
}

var warnedOfIE6Degradation = false;
Util.warnOfIE6Degradation = function() {
  if(Util.isIE6()) {
    $('incompatibleHeader').show();
    $$('.globe').each(function(el) { el.style.visibility = "hidden"; })
  }
}

// hide/show InconcealableElements -- works around certain browsers' behavior
// of displaying Flash elements on top of everything else regardless of
// containment or z-index. These are always meant to be called as a pair.

// XXX These break if there is an inconcealable element in an overlay which
//     wants to be hidden by an even higher overlay. I hope we can avoid this as
//     keeping track would be a sizeable pain.
// XXX These break if any of the inconcealable elements were hidden to begin
//     with. We'd need to keep a list for this too.

Util.inconcealableElementHidingDepth = 0;
Util.inconcealableElementSignature = 'object,embed,#donationsChart';
if(Prototype.Browser.IE) Util.inconcealableElementSignature += ',select';

Util.hideInconcealableElements = function() {
  Util.inconcealableElementHidingDepth++;
  // SELECT is added here for IE6 only, so we may want to restrict it to IE6
  // if(Util.isWindows()) {
    $$(Util.inconcealableElementSignature).each(function(el) { el.style.visibility = "hidden"; });
  // }
}

Util.showInconcealableElements = function() {
  Util.inconcealableElementHidingDepth--;
  if(/*Util.isWindows() && */Util.inconcealableElementHidingDepth == 0) {
    $$(Util.inconcealableElementSignature).each(function(el) { el.style.visibility = "visible"; });
  }
}

// The next three charming yet overcommented functions have been borrowed from
// http://www.hunlock.com/blogs/Totally_Pwn_CSS_with_Javascript
Util.getCSSRule = function(ruleName, deleteFlag) {        // Return requested style obejct
   ruleName=ruleName.toLowerCase();                       // Convert test string to lower case.
   if (document.styleSheets) {                            // If browser can play with stylesheets
      for (var i=0; i<document.styleSheets.length; i++) { // For each stylesheet
         var styleSheet=document.styleSheets[i];          // Get the current Stylesheet
         var ii=0;                                        // Initialize subCounter.
         var cssRule=false;                               // Initialize cssRule.
         do {                                             // For each rule in stylesheet
            if (styleSheet.cssRules) {                    // Browser uses cssRules?
               cssRule = styleSheet.cssRules[ii];         // Yes --Mozilla Style
            } else {                                      // Browser usses rules?
               cssRule = styleSheet.rules[ii];            // Yes IE style.
            }                                             // End IE check.
            if (cssRule)  {                               // If we found a rule...
               if (cssRule.selectorText.toLowerCase()==ruleName) { //  match ruleName?
                  if (deleteFlag=='delete') {             // Yes.  Are we deleteing?
                     if (styleSheet.cssRules) {           // Yes, deleting...
                        styleSheet.deleteRule(ii);        // Delete rule, Moz Style
                     } else {                             // Still deleting.
                        styleSheet.removeRule(ii);        // Delete rule IE style.
                     }                                    // End IE check.
                     return true;                         // return true, class deleted.
                  } else {                                // found and not deleting.
                     return cssRule;                      // return the style object.
                  }                                       // End delete Check
               }                                          // End found rule name
            }                                             // end found cssRule
            ii++;                                         // Increment sub-counter
         } while (cssRule)                                // end While loop
      }                                                   // end For loop
   }                                                      // end styleSheet ability check
   return false;                                          // we found NOTHING!
}                                                         // end getCSSRule
Util.killCSSRule = function(ruleName) {                   // Delete a CSS rule
   return Util.getCSSRule(ruleName,'delete');             // just call getCSSRule w/delete flag.
}                                                         // end killCSSRule
Util.addCSSRule = function(ruleName) {                    // Create a new css rule
   if (document.styleSheets) {                            // Can browser do styleSheets?
      if (!Util.getCSSRule(ruleName)) {                   // if rule doesn't exist...
         if (document.styleSheets[0].addRule) {           // Browser is IE?
            document.styleSheets[0].addRule(ruleName, null,0);      // Yes, add IE style
         } else {                                         // Browser is IE?
            document.styleSheets[0].insertRule(ruleName+' { }', 0); // Yes, add Moz style.
         }                                                // End browser check
      }                                                   // End already exist check.
   }                                                      // End browser ability check.
   return Util.getCSSRule(ruleName);                      // return rule we just created.
}

// Create Twitteresque field maxlength countdowns
var FieldCountdown = Class.create({
  initialize: function(field, target) {
    this.field = $(field);
    this.target = $(target);
    this.max = parseInt(this.field.attributes.maxlength.value);
    new Form.Element.Observer(this.field, 0.2, this.update.bind(this));
    this.update(); // Do the initial update
  },

  update: function() {
    var remain = this.max - this.field.value.length;
    if(!this.field.prompting && remain < (this.max * 0.2)) {
      if(remain < 0) {
        this.target.update("<span class=\"countdownRemain\">" + (-remain) + "</span> characters over limit");
        this.target.addClassName("countdownOver");
      } else {
	this.target.update("<span class=\"countdownRemain\">" + remain + "</span> characters left");
	this.target.removeClassName("countdownOver");
      }
    } else if(this.target.visible()) { // Nothing to display, hide if necessary
      this.target.update("");
    }
  }
});
   
// Our own subclass of Ajax.Autocompleter for incremental search
var IncrementalSearcher = Class.create(Ajax.Autocompleter, {
  // Allow display of a "no results" element
  render: function($super) {
    $super();
    if(this.entryCount > 0) {
      $('searchNoResults').hide();
    } else {
      $('searchNoResults').show();
    }
  },
  show: function($super,event) {
    $super();
  },
  // Hide the "no results" element
  hide: function($super,event) {
    $super();
    $('searchNoResults').hide();
  },
  // Thwart unwanted bubbling of click event to upstream handlers
  onClick: function($super, event) {
    $super(event);
    event.stop();
  },
  onKeyPress: function($super,event) {
    $super(event);
    if(this.changed) {
      document.orgPickerFirst=0;
    }
  }
});

function reflectSelectedLevelOnLoad(times) {
  if( times > 0 ) {
    $$('#suggestedLevels TR INPUT').each(function(e){
      if(e.checked) selectDonationLevel(e);
    });
    setTimeout(function(){reflectSelectedLevelOnLoad(times-1);}, 50);
  }
}
function selectDonationLevel(el) {
  $$('#suggestedLevels TR').each(function(e){
    e.removeClassName("selected");
  });
  el.up('TR').addClassName('selected');
}

var orgPickerActive = false;
function orgPickerClick(first) {
  try {
    if(orgPickerActive) return;
    orgPickerActive = true;
    document.orgPickerFirst=first;
    var s=document.orgPickerSearcher;
    $('org_picker_kw').focus();
    s.activate();
  } finally {
    orgPickerActive = false;
  }

  var reshow = function() {
    if(!$('searchNoResults').visible()) {
      $('orgSearchResults').show();
    }
  };
  for(var i=0; i<5; i++) {
    setTimeout(reshow,100*i);
  }
}
