/**
 * @class $
 * Provides utily functions for DOM elements (addClass, setStyle, event handling, domQuery etc..)
 * @singleton
 * @author Christophe Eblé
 */
 
(function() {
    
  var view = document.defaultView;
  var patterns = {
    HYPHEN: /(-[a-z])/i,      // to normalize get/setStyle
    ROOT_TAG: /^body|html$/i  // body for quirks mode, html for standards
  };
  var propCache = {};
      
  /* private constructor */
  
  function _$(els) {
    this.dom = null;
    this.elements = [];
    for (var i=0; i<els.length; i++) {
      var element = els[i];
      if (typeof element == 'string') {
        element = document.getElementById(element);
        this.dom = element;
      }
      this.elements.push(element);
    }
    return this;
  }

  _$.prototype = {
    each: function(fn) {
      for ( var i = 0, len = this.elements.length; i<len; ++i ) {
        fn.call(this, this.elements[i]);
      }
      return this;
    },
    getEl : function() {
        return this.elements[0];
    },
    toCamelCase : function(property) {
        if (!patterns.HYPHEN.test(property)) {
            return property; // no hyphens
        }
        if (propCache[property]) { // already converted
            return propCache[property];
        }
        var converted = property;
        while(patterns.HYPHEN.exec(converted)) {
            converted = converted.replace(RegExp.$1,
                    RegExp.$1.substr(1).toUpperCase());
        }
        propCache[property] = converted;
        return converted;    
    },
    /**
    * Returns the CSS literal text
    * works only with one element
    * @TODO : Make it work for multiple elements :D
    */
    getStyle : function(prop){
        return view && view.getComputedStyle ?
            function(prop){
                if(typeof this.elements[0] != "undefined") {
                    var el = this.elements[0];
                    var value = null;
                    
                    if (prop == 'float') { // fix reserved word
                        prop = 'cssFloat';
                    }
        
                    var computed = view.getComputedStyle(el, '');
                    if (computed) {
                        value = computed[this.toCamelCase(prop)];
                    }
                    return el.style[prop] || value;
                }
                return false;
            } :
            function(prop){
                switch(this.toCamelCase(prop)) {
                    case 'opacity' : // IE opacity uses filter
                        var val = 100;
                        try { // will error if no DXImageTransform
                            val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;
    
                        } catch(e) {
                            try { // make sure its in the document
                                val = el.filters('alpha').opacity;
                            } catch(e) {
                            }
                        }
                        return val / 100;
                    case 'float': // fix reserved word
                        prop = 'styleFloat'; // fall through
                    default: 
                        // test currentStyle before touching
                        var value = el.currentStyle ? el.currentStyle[prop] : null;
                        return ( el.style[prop] || value );
                }
            };
    }(),
    setStyle: function(prop, val) {
      this.each(function(el) {
        el.style[prop] = val;
      });
      return this;
    },
    addClass: function(className) {
      var regcls = new RegExp('(\\s|^)'+className+'(\\s|$)');
      this.each(function(el) {
        if (!el.className.match(regcls)) {
            el.className += '' + className + '';
        }
      });
      return this;
    },
    removeClass : function(className) {
        var regcls = new RegExp('(\\s|^)'+className+'(\\s|$)');
        this.each(function(el) {
            if (el.className.match(regcls)) {
                el.className = el.className.replace(regcls,'');
            }
        });
        return this;        
    },
    on: function(type, fn) {
      var listen = function(el) {
        if (window.addEventListener) {
          el.addEventListener(type, fn, false);
        } else if (window.attachEvent) {
          el.attachEvent('on'+type, function() {
            fn.call(el, window.event);
          });
        }
      };
      this.each(function(el) {
        listen(el);
      });
      return this;
    },
    css: function(o) {
      var that = this;
      this.each(function(el) {
        for (var prop in o) {
          that.setStyle(prop, o[prop]);
        }
      });
      return this;
    },
    setHtml : function(html) {
      this.each(function(el) {
        el.innerHTML = html;
      });
      return this;
    },
    query : function(selector) {
        if(typeof DomQuery == "object") {
            return DomQuery.select(selector, this.elements[0]);
        }
        return this;
    }
  };
  window.$ = function() {
    return new _$(arguments);
  }
})();

Function.prototype.bind = function(object) {
    var __method = this;
    return function() {
        return __method.apply(object, arguments);
    }
}

function Ajax(property){

    var url = property.url;
    var data = '';
    for (j in property.data)
        data += "&" + j + "=" + escape(property.data[j]);
    var method = property.method || 'POST';
    var async = property.async;
    var onComplete = property.onComplete;
    var returnFormat = property.returnFormat || "xml";
    var response = null;

    if (window.XMLHttpRequest)
       this.obj = new XMLHttpRequest();
    else if (window.ActiveXObject)
         this.obj = new ActiveXObject("Microsoft.XMLHTTP");

    this.obj.open(method,url,async);
    if (method == "POST")
       this.obj.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
    if (async){
        this.obj.onreadystatechange = function () {
            if (this.obj.readyState == 4 && this.obj.status == 200)
            {
                if (returnFormat != "txt")
                    response = this.obj.responseXML;
                else 
                    response = this.obj.responseText;
                onComplete(response);
            }
        }.bind(this)
        this.obj.send(data);
    } else {
        this.obj.send(data);
        if (this.obj.status == "200"){
            if (returnFormat != "txt")
                response = this.obj.responseXML;
            else response = this.obj.responseText;
            onComplete(response);
        }
    }
}