dojo.provide("struts.widget.Bind");

dojo.require("dojo.widget.HtmlWidget");
dojo.require("dojo.io");

dojo.widget.defineWidget(
  "struts.widget.Bind",
  dojo.widget.HtmlWidget, {
  widgetType : "Bind",
  executeScripts : false,
  targets : "",
  targetsArray : null,
  href : "",
  handler : "",

  //messages
  loadingText : "Loading...",
  errorText : "",
  showError : true,
  showLoading : true,

  //pub/sub events
  listenTopics : "",
  notifyTopics : "",
  notifyTopicsArray : null,

  //callbacks
  beforeLoading : "",
  afterLoading : "",

  formId : "",
  formFilter : "",
  formNode : null,

  event : "",
  indicator : "",

  parseContent : true,
  postCreate : function() {
    var self = this;

    //attach listeners
    if(!dojo.string.isBlank(this.listenTopics)) {
      this.log("Listening to " + this.listenTopics + " to refresh");
      var topics = this.listenTopics.split(",");
      if(topics) {
        if(topics) {
          if(topics) {
            dojo.lang.forEach(topics, function(topic){
              dojo.event.topic.subscribe(topic, self, "reloadContents");
            });
          }
        }
      }
    }

    if(!dojo.string.isBlank(this.notifyTopics)) {
      this.notifyTopicsArray = this.notifyTopics.split(",");
    }

    if(!dojo.string.isBlank(this.targets)) {
      //split targets
      this.targetsArray = this.targets.split(",");
    }

    if(!dojo.string.isBlank(this.event)) {
      dojo.event.connect(this.domNode, this.event, function(evt) {
        evt.preventDefault();
        evt.stopPropagation();
        self.reloadContents();
      });
    }

    if(dojo.string.isBlank(this.href) && dojo.string.isBlank(this.formId)) {
      //no href and no formId, we must be inside a form
      this.formNode = dojo.dom.getFirstAncestorByTag(this.domNode, "form");
    } else {
      this.formNode = dojo.byId(this.formId);
    }

    if(this.formNode && dojo.string.isBlank(this.href)) {
      this.href = this.formNode.action;
    }

    if(!dojo.string.isBlank(this.formId)) {
      this.formNode = dojo.byId(this.formId);
    }
  },

  log : function(text) {
    dojo.debug("[" + (this.widgetId ? this.widgetId : "unknown")  + "] " + text);
  },

  setContent : function(text) {
    if(this.targetsArray) {
      var self = this;
	  var xmlParser = new dojo.xml.Parse();
      dojo.lang.forEach(this.targetsArray, function(target) {
        var node = dojo.byId(target);
        node.innerHTML = text;

        if(self.parseContent && text != self.loadingText){
          var frag  = xmlParser.parseElement(node, null, true);
          dojo.widget.getParser().createSubComponents(frag, dojo.widget.byId(target));
		}
      });
    }
  },

  bindHandler : function(type, data, e) {
     //hide indicator
     dojo.html.hide(this.indicator);

     //post script
     if(!dojo.string.isBlank(this.afterLoading)) {
       this.log("Executing " + this.afterLoading);
       eval(this.afterLoading);
     }
     //publish topics
     this.notify(data, type, e);

     if(type == "load") {
       if(this.executeScripts) {
         //update targets content
         var parsed = this.parse(data);
         //eval scripts
         if(parsed.scripts && parsed.scripts.length > 0) {
           var scripts = "";
           for(var i = 0; i < parsed.scripts.length; i++){
             scripts += parsed.scripts[i];
           }
           (new Function('_container_', scripts+'; return this;'))(this);
         }
         this.setContent(parsed.text);
       }
       else {
         this.setContent(data);
       }
     } else {
       if(this.showError) {
         var message = dojo.string.isBlank(this.errorText) ? e.message : this.errorText;
         this.setContent(message);
       }
     }
  },

  notify : function(data, type, e) {
    if(this.notifyTopicsArray) {
      var self = this;
      dojo.lang.forEach(this.notifyTopicsArray, function(topic) {
        try {
          dojo.event.topic.publish(topic, data, type, e);
        } catch(ex){
		  self.log(ex);
        }
      });
    }
  },

  onDownloadStart : function(event) {
    if(!dojo.string.isBlank(this.beforeLoading)) {
      //for backward compatibility
      var data = null;
      var type = null;

      eval(this.beforeLoading);
    }
    if(this.showLoading && !dojo.string.isBlank(this.loadingText)) {
      event.text = this.loadingText;
    }
  },

  reloadContents : function(evt) {

    if(!dojo.string.isBlank(this.handler)) {
      //use custom handler
      this.log("Invoking handler: " + this.handler);
      window[this.handler](this, this.domNode);
    }
    else {
      //pre script
      if(!dojo.string.isBlank(this.beforeLoading)) {
        this.log("Executing " + this.beforeLoading);
        //backward compatibility
        var data = null;
        var type = null;

        eval(this.beforeLoading);
      }

      try {
          var self = this;
          var request = {cancel: false};
          this.notify(this.widgetId, "before", request);
          if(request.cancel) {
            this.log("Request canceled");
            return;
          }

          //if the href is null, we still call the "beforeLoading"
          // and publish the notigy topics
          if(dojo.string.isBlank(this.href)) {
            return;
          }

          //if there is a parent form, and it has a "onsubmit"
          //execute it, validation is usually there
          if(this.formNode && this.formNode.onsubmit != null) {
            var makeRequest = this.formNode.onsubmit.call(evt);
            if(makeRequest != null && !makeRequest) {
              this.log("Request canceled by 'onsubmit' of the form");
              return;
            }
          }

          //show indicator
          dojo.html.show(this.indicator);
		  if(this.showLoading) {
            this.setContent(this.loadingText);
          }

          dojo.io.bind({
            url: this.href,
            useCache: false,
            preventCache: true,
            formNode: self.formNode,
            formFilter: window[self.formFilter],
            handler: function(type, data, e) {
              dojo.lang.hitch(self, "bindHandler")(type, data, e);
            },
            mimetype: "text/html"
         });
      }
      catch(ex) {
        var message = dojo.string.isBlank(this.errorText) ? ex : this.errorText;
        this.setContent(message);
      }
    }
  },

  //from Dojo's ContentPane
  parse : function(s) {
    this.log("Parsing: " + s);
    var match = [];
    var tmp = [];
    var scripts = [];
    while(match){
      match = s.match(/<script([^>]*)>([\s\S]*?)<\/script>/i);
      if(!match){ break; }
      if(match[1]){
        attr = match[1].match(/src=(['"]?)([^"']*)\1/i);
        if(attr){
          // remove a dojo.js or dojo.js.uncompressed.js from remoteScripts
          // we declare all files with dojo.js as bad, regardless of folder
          var tmp2 = attr[2].search(/.*(\bdojo\b(?:\.uncompressed)?\.js)$/);
          if(tmp2 > -1){
            this.log("Security note! inhibit:"+attr[2]+" from  beeing loaded again.");
          }
        }
      }
      if(match[2]){
        // strip out all djConfig variables from script tags nodeValue
        // this is ABSOLUTLY needed as reinitialize djConfig after dojo is initialised
        // makes a dissaster greater than Titanic, update remove writeIncludes() to
        var sc = match[2].replace(/(?:var )?\bdjConfig\b(?:[\s]*=[\s]*\{[^}]+\}|\.[\w]*[\s]*=[\s]*[^;\n]*)?;?|dojo\.hostenv\.writeIncludes\(\s*\);?/g, "");
        if(!sc){ continue; }

        // cut out all dojo.require (...) calls, if we have execute
        // scripts false widgets dont get there require calls
        // does suck out possible widgetpackage registration as well
        tmp = [];
        while(tmp){
          tmp = sc.match(/dojo\.(?:(?:require(?:After)?(?:If)?)|(?:widget\.(?:manager\.)?registerWidgetPackage)|(?:(?:hostenv\.)?setModulePrefix))\((['"]).*?\1\)\s*;?/);
          if(!tmp){ break;}
          sc = sc.replace(tmp[0], "");
        }
        scripts.push(sc);
      }
      s = s.replace(/<script[^>]*>[\s\S]*?<\/script>/i, "");
    }

    return {
      text: s,
      scripts: scripts
    };
  }
});



