// ====================
// = Global variables =
// ====================

// Setting dirtiness_message will cause javascript alert to execute when a user attempts
// to navigate away from the page
var dirtinessHash = new Hash();


// =============================================
// = Extensions to Prototype's element methods =
// =============================================
Element.addMethods({
  toggleClassName: function(element, className) {
    if(!(element = $(element))) return;
    element.hasClassName(className) ? element.removeClassName(className) : element.addClassName(className);
    return element;
  }
})


// ===============================
// = Generic Sliderule Namespace =
// ===============================
var Sliderule = {  
  upwardFrom: function(element, visitor) {
    while (element = $(element)) {
      if (visitor(element)) return element;
      element = element.parentNode;
    }
  },
  getParentElementWithTagNameFor: function(element, parentTagName) {
    return Sliderule.upwardFrom(element, function(e) {
      if (e.tagName == parentTagName) return true;
    });
  },  
  getParentElementWithClassNameFor: function(element, parentClassName) {
    return Sliderule.upwardFrom(element, function(e) {
      if (e.hasClassName) return e.hasClassName(parentClassName);
    });
  }
}

// =========================
// = Form specific helpers =
// =========================
Sliderule.Form = {
  getFormItemForElement: function(element) {
    return Sliderule.upwardFrom(element, function(e) {
      if (e.hasClassName) return e.hasClassName("form-item");
    });
  },
  getFormForElement: function(element) {
    return Sliderule.upwardFrom(element, function(e) {
      if (e.tagName == "FORM") return true;
    });
  }
}


// ======================================================
// = Highlights the container form-item of focused divs =
// ======================================================
var FieldHighlighter = {
  
  // Css class that will be applied when a field is in focus
  focusClassName: 'focused',
  
  start: function() {
    if (!this.focusObserver) {
      this.focusObserver = this.onFocusCapture.bind(this);
      this.blurObserver = this.onBlurCapture.bind(this);
      $$('div.form-item input').each(this.attachObververs);
      $$('div.form-item textarea').each(this.attachObververs);
      $$('div.form-item select').each(this.attachObververs);
    }
  },
  
  attachObververs: function(element) {
    Event.observe(element, "focus", FieldHighlighter.focusObserver);
    Event.observe(element, "blur", FieldHighlighter.blurObserver);
  },
  
  onFocusCapture: function(event) {
    var element = Element.extend(Event.element(event));
    var formItem = Sliderule.Form.getFormItemForElement(element);
    if (formItem) {
      formItem.addClassName(this.focusClassName);
    }
  },
  
  onBlurCapture: function(event) {
    var element = Element.extend(Event.element(event));
    var formItem = Sliderule.Form.getFormItemForElement(element);
    if (formItem) {
      formItem.removeClassName(this.focusClassName);
    }
  }
}


// =======================================
// = Checks for dirtiness on page unload =
// =======================================
var DirtinessChecker = {
  
  dirtyClassName: "dirty",
  
  start: function() {
    if (!DirtinessChecker.saveObserver) {
      window.onbeforeunload = this.confirmExit;
      this.saveObserver = DirtinessChecker.onSaveClick.bind(this);
      $$('input[type=submit]').each(function(element) {
        Event.observe(element, "click", DirtinessChecker.saveObserver);
      });
      $$('input[type=image]').each(function(element) {
        Event.observe(element, "click", DirtinessChecker.saveObserver);
      });
    }
  },
  
  // Remove the form from the dirtiness cache
  onSaveClick: function(event) {
    var element = Element.extend(Event.element(event));
    var formId = this.getFormIdForElement(element);
    dirtinessHash.unset(formId);
  },
  
  getFormIdForElement: function(element) {
    var form = Sliderule.upwardFrom(element, function(e) {
      if (e.tagName == 'FORM') return true;
    })
    if (form) return form.readAttribute('id');
  },
  
  checkField: function(element, value, originalValue) {
    if (value != originalValue)
      Sliderule.Form.getFormItemForElement(element).addClassName(this.dirtyClassName);
    else
      Sliderule.Form.getFormItemForElement(element).removeClassName(this.dirtyClassName);
  },
  
  addMessage: function(formId, message) {
    if (formId) dirtinessHash.set(formId, message);
  },
  
  confirmExit: function () {
    if(dirtinessHash.size() > 0) 
      return DirtinessChecker.dirtinessMessage();
  },
  
  dirtinessMessage: function() {
    var message = "";
    dirtinessHash.each(function(pair) {
      if (message != "") message += '\n';
      message += pair.value;
    });
    return message;
  }
}


// ===========================================
// = Used for select boxes that submit a URL =
// ===========================================
var DropSelector = {
  
  start: function() {
    if (!this.blurObserver) {
      this.changeObserver = this.onChangeSelection.bind(this);
      $$('select.drop_selector').each(function(element) {
        Event.observe(element, "change", DropSelector.onChangeSelection);
      });
    }
  },
  
  onChangeSelection: function(event) {
    var element = Element.extend(Event.element(event));
    if(element.value)
      window.location = element.value;
  }
}


// =================================================
// = Generic toggle link, used for confirm sliders =
// =================================================
var Toggler = {
  
  // Toggles visibility of an element and changes the text of the toggle link
  // First closes any open confirm divs
  toggleElement: function(element, close_confirms) {
    
    // Make sure there that only one confirm animation can run at a time
    if(Effect.Queues.get('confirm').size() > 0) return;
    
    if(!(element = $(element))) return;
    
    // First close all open confirm divs, unless asked not to
    if(close_confirms == null || close_confirms == true) {
      $$('.closeable').each(function(e) {
        // Make sure we don't attempt to close the selected elemtent
        if(e.id != element.id) Toggler.closeElement(e);
      });
    }
    
    // Now toggle the chosen div
    var link_id = element.id + "_toggle_link";
    new Effect.toggle(element,'blind',{
      queue: {position: 'end', scope: 'confirm'},
      afterFinish: function(obj) {
        var tmp_string = $(link_id).innerHTML;
        $(link_id).update($(link_id).readAttribute('alternate_text'));
        $(link_id).setAttribute('alternate_text', tmp_string);
      }
    });
  },
  
  // Close the element if it is open
  closeElement: function(element) {
    if(!(element = $(element))) return;
    if(element.style.display != 'none') {
      Toggler.toggleElement(element, false);
    }
  }
}

// ================================================================================
// = Gives a field default text that is cleared when the user clicks in the field =
// ================================================================================
var ExampleText = {
  start: function() {
    if (!this.focusObserver) {
      this.focusObserver = this.onFocusField.bind(this);
      $A(document.getElementsByTagName('input')).each(function(element) {
        if(element.readAttribute('example_text')) {
          
          ExampleText.setExampleText(element);
          
          // Set up the form to ignore default text
          Element.observe(Sliderule.Form.getFormForElement(element), 'submit', ExampleText.onSubmitForm);
          
          // Set up an observers
          Event.observe(element, "focus", ExampleText.onFocusField);
          Event.observe(element, "blur", ExampleText.onBlurField);
        }
      });
    }
  },

  onFocusField: function(event) {
    var element = Element.extend(Event.element(event));
    ExampleText.clearExampleText(element);
  },

  onBlurField: function(event) {
    var element = Element.extend(Event.element(event));
    ExampleText.setExampleText(element);
  },

  onSubmitForm: function(event) {
    var form = Element.extend(Event.element(event));
    
    // Go through each of the form inputs and clear them if they are set to default text
    form.getInputs().each(function(input) {
      
      // If the value is the example text, then clear its value
      if(input.readAttribute('example_text')) {
        ExampleText.clearExampleText(input);
      }
    });
    return true;
  },
  
  setExampleText: function(element) {
    // If the value is blank, then reset the example text
    if(/^\s*$/.test(element.value)) {
      element.addClassName('example-text');
      element.value = element.readAttribute('example_text');
    }
  },
  
  clearExampleText: function(element) {
    // If the value is the example text, then clear its value
    if(element.value == element.readAttribute('example_text')) {
      element.value = '';
      element.removeClassName('example-text');
    }
  }
}


// ====================================
// = Swap default and alternate lists =
// ====================================
var Swappable = {
  swap: function(element, toggleEffect) {
	
    // Make sure only one animation can run at once
    if(Effect.Queues.get('swappable_queue').size() > 0) return;
  
    if(!(element = $(element))) return;
  
    // Find the container, through which we will find the current and alternate lists
    var container = Sliderule.upwardFrom(element, function(e) {
      if (e.hasClassName) return e.hasClassName("swappable_container");
    });

    // Look for the current and alternate lists
    for (var i = 0; i < container.immediateDescendants().length; ++i) {
      var e = container.immediateDescendants()[i];
      if(e.hasClassName('alternate_items')) {
        var alternateItems = e;
      } else if(e.hasClassName('default_items')) {
        var defaultItems = e;
      }
    }
  
		toggleEffect = typeof(toggleEffect) != 'undefined' ? toggleEffect : 'blind';

    if(defaultItems.style.display != 'none') {
      new Effect.toggle(defaultItems, toggleEffect, {queue: {position:'end', scope: 'swappable_queue'}});
      new Effect.toggle(alternateItems, toggleEffect, {queue: {position:'end', scope: 'swappable_queue'},
                                                  afterFinish: this.toggleControlLink(element)});
    } else {
      new Effect.toggle(alternateItems, toggleEffect, {queue: {position:'end', scope: 'swappable_queue'}});
      new Effect.toggle(defaultItems, toggleEffect, {queue: {position:'end', scope: 'swappable_queue'},
                                                afterFinish: this.toggleControlLink(element)});
    }
  
  },

  toggleControlLink: function(element) {
    var tmp_string = element.innerHTML;
    element.update(element.readAttribute('alternate_text'));
    element.setAttribute('alternate_text', tmp_string);
  }
}

// ===================
// = Rounded corners =
// ===================
var Corners = {
  start: function() {
    // Sidebar boxes
    $A(['box', 'rounded']).each(function(klass) {
      var corneredObject = new curvyCorners({
                                              tl: { radius: 5 },
                                              tr: { radius: 5 },
                                              bl: { radius: 5 },
                                              br: { radius: 5 },
                                              antiAlias: true,
                                              autoPad: true,
                                              validTags: ["div"]
                                            }, 
                                            klass);
      corneredObject.applyCornersToAll();
    });
  }
}


// ============================
// = Initialize all observers =
// ============================
Event.observe(window, "load", function() {
  Corners.start();
  DropSelector.start();
  FieldHighlighter.start();
  DirtinessChecker.start();
  ExampleText.start();
});

// =====================================================================
// = Remove phone number from the list.  Can be for supplier or person =
// =====================================================================
var PhoneNumber = {  
  remove: function(element, allowRemoveLastElement) {
    var phone_list = Sliderule.getParentElementWithTagNameFor(element, 'UL');
    if (!allowRemoveLastElement && phone_list.immediateDescendants().size() == 1)
      alert("You must have at least one phone number.");
    else {
      var phone = Sliderule.getParentElementWithClassNameFor(element, 'phone-number-list-item');
      phone.remove();
    }    
  }
}
