var PraxeonObject = {
 create : function() {
    function F(){}
    F.prototype = this;
    var o = new F();
    o.initialize.apply(o, arguments);
    return o;
  },
 
 initialize : function() {
    //placeholder
    //sub-objects override this
  },
 
 //Extend an object with another's properties and methods
 extend : function(target, definition) {
    for(var i in definition) {
      var val = definition[i];
      target[i] = val;
    }
    return target;
  },
 
 /* Use this to create a new Praxeon object, the new object's prototype will be this object
    The object returned can be 'instantiated' with .create() */
 construct : function(definition) {
    var o = this.create();
    return this.extend(o, definition);
  }
};

var PraxeonWidget = PraxeonObject.construct({
    //shared table for callbacks
    callbacks : {
	'callback' : function() {
	    //the default, does nothing
	}
    },
      
    /* Accessor functions so widgets that inherit from here can get to the callback table */
    set_callback : function(callback_name, fn) {
	PraxeonWidget.callbacks[callback_name] = fn;
    },
    
    get_callback : function(callback_name) {
	if(callback_name) {
	    return PraxeonWidget.callbacks[callback_name];
	}
    },
    
    run_callback : function() {
	var callback_name = arguments[0];
	if(callback_name) {
	    var args = [];
	    for(var i=1; i< arguments.length; i++) {
		args.push(arguments[i]);
	    }
	    var fn = PraxeonWidget.get_callback(callback_name);
	    if(fn) {
		fn.apply(null, args);
	    }
	}
    },
    

    /* Useful methods for sub-widgets */

    generate_unique_callback_string : function() {
	    var str = 'callback_';
	    var choices = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
	    for(var i=0; i<11;i ++) {
		str = str + choices[Math.round(Math.random() * (choices.length - 1))]
	    }
	    if(!PraxeonWidget.get_callback(str)) {
		return str;
	    }
	    else {
		return this.generate_unique_callback_string();
	    }
     },

     is_element : function(el_or_id) {
           return el_or_id.constructor != String; //this could be better...
     },

     element_for_element_or_id : function(el_or_id) {
	   if(this.is_element(el_or_id)) {
	       return el_or_id
	   }
	   else {
	       return document.getElementById(el_or_id);
	   }    
     },

     insert_script_tag : function(url) {
          var script_el = document.createElement('script');
	  script_el.setAttribute('src', url);
	  document.body.appendChild(script_el);
	  return script_el;
     }

});


var NewsWidget = PraxeonWidget.construct({

	element : null,
	limit : null,
	linkTarget : null,

	initialize : function(token, destination_element_or_id, limit) {
	    this.token = token;
	    this.element = this.element_for_element_or_id(destination_element_or_id);
	    this.limit = limit;
	},

	draw_widget : function(html) {
	    this.element.innerHTML = html;
	},

	show_loading_message : function() {
	    this.element.innerHTML = "<div class='header' style='width: 95%;'><img src='/shared/images/ECGAnim.gif'>&nbsp;&nbsp;<b>Fetching news from MyDailyApple...</b></div>";
	},

	fetch_news : function() {
	    this.show_loading_message();
	    
	    var calling_widget = this;
	    var insert;

	    var callback_string = this.generate_unique_callback_string();
	    this.set_callback(callback_string, function(html) {
		    calling_widget.draw_widget(html);
		    //clean up
		    calling_widget.set_callback(callback_string, null);
		    if(insert && insert.parentNode) {
			insert.parentNode.removeChild(insert);
		    }
		});

	    var script_url = 'http://www.mydailyapple.com/widget_results/news?token=' + encodeURIComponent(this.token) + '&callback=' + callback_string + '&format=js';
    	if ( this.limit != null ) script_url += '&limit=' + this.limit;
    	if ( this.linkTarget != null ) script_url += '&linkTarget=' + this.linkTarget;
	    insert = this.insert_script_tag(script_url);
	}
    });
