Widget = Class.create({
    setProperties: function(args) {
        Object.extend(this, args);
    }, 
    initialize: function(o) {  
        if (o) this.setProperties(o);  
        //console.log("Widget.init: "+this.id); 
        this.domNode = false;
        this.children = []; 
        
        if (this.templatePath||this.templateString) {
            this.mixInProperties();
        } else { //widget has no template    
            if ($(this.id))  $(this.id).widget = this; 
            this.create();  
        } 
    },
    mixInProperties: function() { 
        //console.log("this.mixInProperties "+this.id+"/"+this.templatePath);
        var key = (this.templateKey ? this.templateKey : this.templatePath);
        var forceReload = (this.forceReload ? this.forceReload : false);
        var params = {key:key, forceReload:forceReload, query: this.query}; 
        if (this.templateString) params.templateString = this.templateString; 
        generic.templatefactory.get(params).evaluateCallback({
            object: this,
            callback: this.handleMixIn.bind(this)
        }); 
    },
    handleMixIn: function(html) { 
        html = html.strip();  
        generic.helpers.div.update(html); 
        this.domNode = generic.helpers.div.firstDescendant();  
    
        var existingContent = false; 
        if ($(this.id)) this.nodeToReplace = $(this.id);
        if (this.nodeToReplace) { //obj with same id might exist, or a different container passed in to be replaced with this node
            //console.log("handleMixIn: this.nodeToReplace "+this.nodeToReplace.id + " /check: "+$("gnav_products"));
            existingContent = this.nodeToReplace.innerHTML; 
            if (this.reinsertNode) {
                //console.log("this.handleMixIn: this.reinsertNode");
                this.nodeToReplace.parentNode.removeChild(this.nodeToReplace); //e.g. psubnav_my_mac
                this.nodeToReplace = false;
            }
        } 
    
        if (this.nodeToReplace) {
            this.updateMixIn();
        } else {
            this.insertMixIn();
        }
        
        var self = this;
        this.domNode.widget = self;     
        this.attachPoints();  
        this.attachEvents();  
        this.containerNode = this.containerNode ? this.containerNode : this.domNode;
        
        if (existingContent) { 
            this.containerNode.insert(existingContent);
        }
        
        this.create(); 
    },
    updateMixIn: function() { 
        //console.log("Widget.updateMixIn: "+this.domNode+" "+this.nodeToReplace.id + " /check: "+$("gnav_products"));
        this.nodeToReplace.parentNode.replaceChild(this.domNode, this.nodeToReplace); 
    },
    insertMixIn: function() {
        if (this.domInsertionMethod) { 
            this.domInsertionMethod(this);
        } else { 
            try {  
                var container = this.domParent ?  this.domParent : $(this.parentId).widget.containerNode;
                if (typeof container == "string") container = $(container); 
                //console.log("this.handleMixIn "+this.id+" // "+container.id);    
                container.insert(this.domNode);   
            } catch(e) {
                console.log("Widget.insertMixIn e: "+this.id+"/"+this.parentId);
            }
        }  
    },
    create: function() {   
        //console.log("Widget.create: "+this.id);   
        if ($(this.parentId) && $(this.parentId).widget) {
            this.parent = $(this.parentId).widget;
            $(this.parentId).widget.children.push(this); 
        } else {
            //console.log("!! Widget.create: "+this.id +" / "+ this.domParent +" / "+ this.parentId +" / "+ $(this.parentId));   
        }       
        
        if (this.postCreate) {
            this.postCreate();   
        } 
    },
    attachPoints: function() { 
        //console.log("Widget.attachPoints "+this.id);    
        var self = this; 
        try {
            var elemsWithPoints = this.domNode.select("[attachPoint]");   
            if (null !== this.domNode.getAttribute("attachPoint")) elemsWithPoints.push(this.domNode);  
            var attachPoint;
        
            elemsWithPoints.each(function(elem) {   
                attachPoints = String(elem.getAttribute("attachPoint")).split(",");  
                attachPoints.each(function(attachPoint){
                    //console.log("Widget.attachPoints: "+elem.id+"/"+attachPoint);  
                    self[attachPoint] = elem; 
                    self["domNode"].widget[attachPoint] = elem;  
                }); 
        
            });
        } catch(e) {
            console.log("Widget.attachPoints e "+ this.domNode + " " +e.description);   
            return;
        }  
    },
    attachEvents: function() { 
        //console.log("Widget.attachEvents: "+this.id);    
        var self = this; 
        try {
            var elemsWithEvents = this.domNode.select("[attachEvent]"); 
            if (null !== this.domNode.getAttribute("attachEvent")) elemsWithEvents.push(this.domNode);  
            var events, etype, functionName, func; 
        
            elemsWithEvents.each(function(elem) { 
                events = String(elem.getAttribute("attachEvent")).split(",");  
                events.each(function(event){
                    event = event.split(":");
                    etype = event[0];
                    functionName = event[1];
                    func = self[functionName];
                    //console.log('Widget.attachEvents: ' + elem.id + '  attached e ' + functionName + ' e type = '+etype+" func = "+func);   
                    //if (func) elem.observe(etype, func.bind(self)); // ie bug
                    if (func) elem["on"+etype] = func.bind(self);
                }); 
            });
        } catch(e) {
            console.log("Widget.attachEvents e "+ this.domNode + " " +e.description);   
            return;
        }  
    }
});
