/* Establish top-level behavior namespace */
if (typeof ThePoint === 'undefined') {
	ThePoint = {};
}

ThePoint.Application = function () {
	var connectedWithFacebook = false;
	var facebookTemplateBundleId = null;
	
  return {
		// State Helpers
		setConnectedWithFacebook: function() {
			connectedWithFacebook = true;
		},
		isConnectedWithFacebook: function() {
			return connectedWithFacebook == true;
		},
		logOut: function() {
    	window.location.href = "/logout";
		},
		reloadPage: function() {
			window.location.reload(true);
		},

		// Ajax helpers
		get: function(url, parameters) {
			parameters.method = 'get';
			return new Ajax.Request(url, parameters);
		},
		post: function(url, parameters) {
			parameters.method = 'post';
			return new Ajax.Request(url, parameters);
		},
		put: function(url, parameters) {
			parameters.method = 'put';
			return new Ajax.Request(url, parameters);
		},
		del: function(url, parameters) {
			parameters.method = 'delete';
			return new Ajax.Request(url, parameters);
		},
		// General helpers
		popup: function(name, url) {
      return window.open(url, name);
    }
  };
}();

Event.addBehavior.reassignAfterAjax = true;

Element.addMethods({
    setChildAttributes: function(element, selector, attributes) {
        var children, i, attribute;
        children = element.select(selector);
        for (i=0; i < children.length; i+=1) {
          children[i].writeAttribute(attributes);
        }
    }
});

var combineElements = function(a1, a2) {
  var combinations = [];
  a1.each(function(e1) {
    a2.each(function(e2) {
      combinations.push(e1 + e2);
    }, this);
  }, this);
  return combinations;
}

/* 
 * Progress Indicators for asynchronous activity
 */
ProgressIndicator = {}
ProgressIndicator.Spinner = Class.create({
  spinnerElementClass : 'submitRemoteSpinner',
  initialize : function(element, insertion, spinnerUrl) {
    this.sourceElement = element;
    this.insertion = insertion || 'after';
    this.spinnerUrl = spinnerUrl || '/images/icons/spinner.gif'
  },
  start : function() {
    var progress_markup = $span({ 'class' : this.spinnerElementClass }, $img({ src : this.spinnerUrl, border : 0}));
    var position = {};
    position[this.insertion] = progress_markup;
    this.sourceElement.insert(position);
    switch (this.insertion) {
      case 'after':
        this.spinnerElement = this.sourceElement.next();
        break;
      case 'before':
        this.spinnerElement = this.sourceElement.next();
        break;
      case 'top':
        this.spinnerElement = this.sourceElement.childElements().first();
        break;
    }
  },
  stop : function() {
    if (this.spinnerElement.up()) this.spinnerElement.remove();    
  }
});
ProgressIndicator.Spinner.start = function(sourceElement, insertion) {
  var indicator = new this(sourceElement, insertion);
  indicator.start();
  return indicator;
}

Confirmation = Class.create({
  initialize : function(element, decorated) {
    this.element = element;
    this.decorated = decorated;
  },
  onclick : function(e) {
    confirmed = confirm(this.getMessage(e));
    if (confirmed) {
      if (this.decorated) {
        return this.decorated();
      } else {
        return confirmed;
      }
    } else {
      e.stop();
      return false;
    }
  },
  /**
   * @returns the contents of the child element whose CSS class is 'confirmationMessage' of the form containing the submit button,
   *          if the 'confirmationMessage' element exists; otherwise, null.
   */
  getMessage : function(e) {
    var confirmationMessageElement = this.element.childElements().detect(function(childElement) { return childElement.match('.confirmationMessage') });
    return confirmationMessageElement == null ? null : confirmationMessageElement.innerHTML;
  }
});

Confirmation.LinkToRemote = Class.create(Confirmation, {
  getMessage : function(e) {
    var confirmation = this.element.down('.fields > *[name=confirm]');
    if (confirmation)
      confirmation = confirmation.innerHTML;
    else
      confirmation = 'Are you sure?';

    return confirmation;
  }  
});

LinkToRemote = Class.create({
  progressIndicator : ProgressIndicator.Spinner,
  
  initialize : function(element) {
    this.element = element;
  },
  
  makeRequest : function() {
    var url = this.element.down('.fields > *[name=url]').innerHTML;
    var methodField = this.element.down('.fields > .form_data > .method');
    
    parameters = {};
    parameters[methodField.attributes.name.value] = methodField.innerHTML;
    
    new Ajax.Request(url, {
      sourceElement: this.element,
      progressIndication: this.progressIndicator.start(this.element),
      method: methodField.innerHTML,
      parameters: parameters,
      onComplete: function(transport) {
        var options = transport.request.options;
        options.progressIndication.stop();
        Event.addBehavior.reload();        
      }
    });    
  }
});

/* This utility function takes in a css selector, and attaches the passed behavior to
*  any members that have a class that matches the passed regex
*  
*  Used by HelpBubble and ElementToggler
*/
ThePoint.bindBehaviorToCollection = function(selector, BehaviorToInstantiate, regex) {
    return function() {
        document.observe('dom:loaded', function() {
            var i, match, collection, element, b;
            collection = $$(selector);
            for (i=0; i < collection.length; i+=1) {
                element = collection[i];
                match = element.className.match(regex);
                if (match) {
                    b = new BehaviorToInstantiate(element, match[1]);
                }
            }
        });
    }();
};

/* Behavior to hide/show an element when a checkbox is checked/unchecked */
ThePoint.ElementToggler = Behavior.create({
    initialize: function(element) {
        this.elementToToggle = $(element);
        this.sync();
    },
    onchange: function(event) {
        this.sync();
    },
    sync: function() {
        if (this.element.checked) {
            this.show();
        } else {
            this.hide();
        }
    },
    show: function() {
        this.elementToToggle.show();
    },
    hide: function() {
        this.elementToToggle.hide();
    }
});

/* a specialized ElementToggler Behavior that adds enable/disable of any contained input elements 
* on hide/show to prevent posting of hidden elements
*/
ThePoint.DisablingElementToggler = Behavior.create(ThePoint.ElementToggler, {
    show: function($super) {
        $super();
        this.elementToToggle.setChildAttributes('input,select', {disabled:false});
    },
    hide: function($super) {
        $super();
        this.elementToToggle.setChildAttributes('input,select', {disabled:true});
    }
});

/* a specialized DisablingElementToggler Behavior that adds hide/show of another element in tandem 
* with the primary one; a swap view
*/
ThePoint.SwappingElementToggler = Behavior.create(ThePoint.DisablingElementToggler,{
  initialize:function($super, element, swapElement){
    this.swapElement = $(swapElement);
    $super(element);
  },
  show:function($super){
    $super();
    this.swapElement.hide();
    this.elementToToggle.setChildAttributes('input,select', {disabled:true});
  },
  hide: function($super){
    $super();
    this.swapElement.show();
    this.elementToToggle.setChildAttributes('input,select', {disabled:false});
  }
});

/* Behavior to hide/show an element when a link is clicked 
 * default behvior will be cancelled if triggering element has class disabled
 */
ThePoint.LinkElementToggler = Behavior.create(ThePoint.ElementToggler, {
  onclick: function(event) {
    if (!this.disabled()) {
      if (this.elementToToggle.visible()) {
        this.hide();
      } else {
        this.show();
      }
    }
  },
  sync: function() {
    // disable sync so it doesn't toggle on initialize
    // init code can go here for derived classes
    return true;
  },
  show: function() {
    this.elementToToggle.show();
  },
  hide: function() {
    this.elementToToggle.hide();
  },
  disabled: function() {
    return(this.element.hasClassName('disabled'));
  }
});

/* a specialized LinkElementToggler Behavior that adds enable/disable of any contained input elements 
* on hide/show to prevent posting of hidden elements
* define aftershow or afterhide options for callbacks
*/
ThePoint.LinkDisablingElementToggler = Behavior.create(ThePoint.LinkElementToggler, {
    initialize: function($super, element, options) {
      this.options = {};
      if (typeof options != "undefined") this.options = options;
      $super(element);
    },
    onclick: function($super, event) {
      if (this.disabled()) {
        if (this.options['ondisabledclick']) this.options['ondisabledclick'](this.element);
      }
      $super();
    },
    show: function($super) {
      $super();
      this.enableFields();
      if (this.options['aftershow']) this.options['aftershow'](this.element);
    },
    hide: function($super) {
      $super();
      this.disableFields();
      if (this.options['afterhide']) this.options['afterhide'](this.element);
    },
    sync: function () {
      if (this.elementToToggle.visible()) {
        this.enableFields();
      } else {
        this.disableFields();
      }
    },
    enableFields: function() {
      this.elementToToggle.setChildAttributes('input,select', {disabled:false});
    },
    disableFields: function() {
      this.elementToToggle.setChildAttributes('input,select', {disabled:true});
    }
});


/*
  to show textboxes for unit name and price per unit
*/
ThePoint.DropdownElementToggler = Behavior.create(ThePoint.DisablingElementToggler,{
  initialize: function($super, element, activeValue){
    this.activeValue = activeValue;
    $super(element);
  },
  sync: function() {
    if (this.element.value == this.activeValue) {
        this.show();
    } else {
        this.hide();
    }
  }
});





Event.addBehavior({
  'a.remote, #canvas.logged_in a.logged_in_remote, .main a.logged_in_remote' : Behavior.create({
    onclick : function(e) {
      e.stop();
      var sourceElement = e.element();
			if (sourceElement.tagName.toLowerCase() != 'a')
				sourceElement = sourceElement.up('a');
      var linkToRemote = new LinkToRemote(sourceElement);

      if (sourceElement.hasClassName('confirm')) {
        new Confirmation.LinkToRemote(sourceElement, linkToRemote.makeRequest.bind(linkToRemote)).onclick(e);
      } else {
        linkToRemote.makeRequest();
      }
    }
  }),
  'ul.alerts li.error': function() { new Effect.Highlight( this, { startcolor: '#ff6699' }); },
  'ul.alerts li.info': function() { new Effect.Highlight( this, { startcolor: '#ffcc66' }); },
  'ul.alerts li.success': function() { new Effect.Highlight( this, { startcolor: '#ccff66' }); },
  'ul.form_errors': function() { new Effect.Highlight( this, { startcolor: '#ff6699' }); }
});

/* Easy way to leverage our alert messaging via a JS call in RJS templates */
var addAlertViaRJS = function(className, message){
  var alertsList = document.createElement('ul');
  Element.extend(alertsList);
  alertsList.addClassName('alerts');

  var alertItem = document.createElement("li");
  Element.extend(alertItem);
  alertItem.addClassName(className);
  alertItem.innerHTML = message;

  alertsList.insert(alertItem);
  $("alerts").update(alertsList);
}

var addAlert = addAlertViaRJS;

var removeAlert = function(){
  $("alerts").update('');
}



/* Site wide notice 'close' behavior */
Event.addBehavior({
  "#site_notice .notice .close a img:click" : function(event){
		event.stop();
		var siteNotice = event.element().up(".notice");
    siteNotice.hide();
  }
});

Event.addBehavior({
  "#whats_this:click" : function(event) {
    event.stop();
    var page = event.element().readAttribute('href');
    openWindow(page, "help", config="height=300,width=600,resizable=yes,scrollbars=yes");
  }
});

var openWindow = function(page, name, config) {
  window.open(page, name, config);
}

/* attach featured campaign module scroll behavior anywhere you see the module */
document.observe("dom:loaded", function() {  
  var visibleSelector  =  '#featured .active';
  var collectionClass  = "featured_group";    
  var scrollOffsetClass =  ".scroll_offset"; // ff3 hack avoids inconsistent reading of attributes ondomload
  if ($$('#featured a.next_channel').first() != null) {
   	Event.addBehavior({
      '#featured a.next_channel':  ThePoint.SimpleCarousel('next', visibleSelector, collectionClass, scrollOffsetClass), 
      '#featured a.previous_channel':  ThePoint.SimpleCarousel('previous', visibleSelector, collectionClass, scrollOffsetClass) 
    });
  }
})

function catchExternalLinks() {
  $$('a:not([rel~=skip_external])').each(function(el){
    var h = el.readAttribute('href');
    if(h && (h.startsWith('http://') || h.startsWith('https://'))) {
      el.observe('click', function(e){
        e.stop();
        window.open(el.href);
      });
    }
  });
}

document.observe("dom:loaded", function() {
  catchExternalLinks();
});


// Prevent Double click
// a) doesn't interfere with no-javascript,
// b) doesn't work on forms that are already submitting via js .submit

ThePoint.DoubleClickPreventer = Behavior.create({
  disable_form_on_submit: function(event) {
    if(event.element().disabled) {return event.stop();}
    event.element().disable();
    event.element().up('form').submit();
  },

  disable_field_on_submit: function(event) {
    if(event.element().hasClassName('disabled')) {return event.stop();}
    event.element().addClassName('disabled');
  },
  onclick: function(event) {
    if(event.element().tagName == 'FORM') {
      this.disable_form_on_submit(event);
    }
    else {
       this.disable_field_on_submit(event);
    }
  }
});

Event.onReady(function(){
  $$('.disabled_on_submit').each(function(element){
    new ThePoint.DoubleClickPreventer(element);
  });
});


Protoload={timeUntilShow:250,opacity:0.2,startWaiting:function(a,b,d){if(typeof a=="string"){a=document.getElementById(a)}if(b==undefined){b="waiting"}if(d==undefined){d=Protoload.timeUntilShow}a._waiting=true;if(!a._loading){var c=document.createElement("div");(a.offsetParent||document.body).appendChild(a._loading=c);c.style.position="absolute";try{c.style.opacity=Protoload.opacity}catch(c){}try{c.style.MozOpacity=Protoload.opacity}catch(c){}try{c.style.filter="alpha(opacity="+Math.round(Protoload.opacity*100)+")"}catch(c){}try{c.style.KhtmlOpacity=Protoload.opacity}catch(c){}}a._loading.className=b;window.setTimeout((function(){if(this._waiting){var i=this.offsetLeft,h=this.offsetTop,g=this.offsetWidth,e=this.offsetHeight,f=this._loading;f.style.left=i+"px";f.style.top=h+"px";f.style.width=g+"px";f.style.height=e+"px";f.style.display="inline"}}).bind(a),d)},stopWaiting:function(a){if(a._waiting){a._waiting=false;a._loading.parentNode.removeChild(a._loading);a._loading=null}}};if(Prototype){Element.addMethods(Protoload);Object.extend(Element,Protoload)};


// Invoke Lightbox
Event.onReady(function() {
  var lightbox = $$('.lightbox')[0];
  
  if(lightbox) {
    var first_child = lightbox.down('div');
    Control.Modal.open(first_child, {
      beforeOpen: function() {
        $('control_overlay').setStyle({
          width: '100%'
        });
      },
      fade: true,
      overlayOpacity: 0.75
    });
  }
});