// schmedley Widget (schmidget) Class - extends mooTools Element
// any parameters that are common to all schmidgets should be handled in this parseParams method - i.e., x, y
// can not extend Element in MooTools so have to wrap the element reference

var Widget = new Class( {
    Extends: Object,

    initialize: function(type, dbID, desk) { // dbID is the server side uniqueID, used to reference the params
        this.type = type;		       // keep a reference to this
        this.dbID = dbID;
        this.id = type + '__' + dbID;
        this.desk = desk;
        this.x = '0px';         // remember these so we know if we need to update params on mouse up (position changed)
        this.y = '0px'
        this.requests = new Array(); // keep a reference of our outgoing requests to close gracefully
        this.noUpdate = desk.isPublicView;
	this.noDelete = false;

        var src = '/apps/' + this.type + '/';
        this.el = new Element('div', {		// create the schmidget <div> container
            'id': this.id,					// assigns the ID
            'class': 'schmidget'
        });

        // load template
        this.el.set('load', {'async': false})
        this.el.load(src + 'index.html')

        // probably want to move this to post init??  or at least the fade
        this.el.setOpacity(0.0);
        this.el.injectInside(desk.el); 	// injects new schmidget <div> into the current desktop

        // not sure why schmidget style is not obeyed but force this.
        //this.el.setStyles({'top': '100px', 'left': '100px'});

        var self = this;

        // the desk will handle the clicks
        this.el.addEvent('mouseup', function(e) {
            desk.widgetMouseUp(self);
        });

        this.el.addEvent('mousedown', function(e) {

            desk.widgetMouseDown(self);
        });

	this.el.addEvent('keypress', this.cancelAll.bindWithEvent(this));
    },

    postInit: function() {

        // console.log("Widget->postInit");

	var self = this;

        var draggee = this.el; // the draggable container (the schmidget <div>)
        this.dragger = this.el.getElementsByTagName('div')[0]; // the drag handle (first <div> inside the schmidget <div>
        if (this.dragger && draggee) {
            Draggable.init(this.dragger, draggee); // function to initiate the drag feature and attach to the 2 elements above
        }

	// need this so that expand will show in expandable widgets on public pages
        this.el.addEvent('mouseenter', function(e) {
            e = new Event(e).stop();
            self.showClose();
        });
        

        this.el.addEvent('mouseleave', function(e) {
            e = new Event(e).stop();
            self.hideClose();
        });

        if (!this.noUpdate
	    && !this.noDelete){            
            // dynamically attach close button
            this.closeButton = new Element('img', {
                'class': 'widgetClose',
                'src': 'css/img/widget-close.png',
                'title': gls('but3')
            })
		.setOpacity(0.0)
		.addEvent('click', this.closeWidget.bindWithEvent(this))
		.addEvent('mousedown', function(e){ var e = new Event(e).stop()})
		.addEvent('mouseup', function(e){ var e = new Event(e).stop()})
		.inject(this.el);
        }
	
    },

    showClose: function() {
	if (this.closeButton){
            this.closeButton.setOpacity(1.0);
	}
    },

    hideClose: function() {
	// won't have it if on public page
        if (this.closeButton) this.closeButton.setOpacity(0.0);
    },

    positionClose: function(left, top){
        if (this.closeButton) this.closeButton.setStyles({'top': top, 'left': left});
    },

    closeWidget: function(ev) { // used to remove the supporting CSS and JS files for a schmidget after the last instance has been closed/removed
        if (this.closeButton) this.closeButton.removeEvents('click');

        var evt = new Event(ev);
        evt.stop();

        schmedley.fade('out', this.el);

        if (this.updateInterval) $clear(this.updateInterval);

        // clear all other requests
        for(var i = 0; i < this.requests.length; i++){
            this.requests[i].cancel();
        }

        // tell the server to remove the widget
        var self = this;
        var req = new Request.JSON({
            url: "/closeWidget.php", 'async': true, onComplete: function(response) {
                if (response && response.status == 'success') {
                    self.el.destroy.bindWithEvent(self.el).delay(250);
                    self.desk.closeWidget(self);
                    delete schmedley.widgets[self.el.id];
                    schmedley.removeCookieValue(self.type + '_' + self.dbID);
                }
                else {
                    schmedley.alert("Unable to close schmidget.");
                    schmedley.fade('in', self.el);
                    self.closeButton.addEvent('click', self.closeWidget.bindWithEvent(self));
                }
            }
        });
        req.get({'t': this.dbID});

        // trying to be memory efficient here, but what's gained?
        // we may need the CSS and JS if a new widget is created.
        // probably best to just leave them loaded.

        /*
        var schmidgets = $$('div.schmidget').getProperty('id').toString();	// gets an array of all "open" schmidget IDs and converts it to a string

        if (schmidgets.indexOf(schmidgetName) == -1) {		// evaluates wether or not the schmidget name exists in the "open" schmidgets string, if not...
        $(schmidgetName + 'CSS').destroy();		// removes the supprting CSS file for this app from the DOM
        $(schmidgetName + 'JS').destroy();			// removes the supprting CSS file for this app from the DOM
        }
        */
    },


    parseOuterParams: function(params, visible) { // this is to parse params that effect the div wrapper, like x,y
        for (var paramName in params) {
            var updates = new Array();
            var width = window.getSize().x;
            
            var value = params[paramName];
            switch(paramName) {
            case 'x':
		if (value.substring(value.length - 2) == 'px'){
                    valueNum = value.substring(0, value.length - 2);
		}
		else {
		    valueNum = value;
		    value += 'px';
		}
                // this fixes a case where the x position erroneously is offscreen
                if (valueNum > width){
                    value = (width - 250) + 'px';
                    updates['x'] = value;
                }

                this.x = value;
                this.el.setStyle('left', value);
                break;
            case 'y':
		if (value.substring(value.length - 2) != 'px'){
                    value += 'px';
                }
                this.y = value;
                this.el.setStyle('top', value);
                break;
            case 'z':
                this.el.style.zIndex = value;
                break;
            case 'isFlash':
                this.isFlash = (value == 1);
                break;
            case 'canPublish':
                this.canPublish = (value == 1);
                break;
	    case 'noDelete':
		this.noDelete = (value == 1);
		break;
            }

            if (updates.length > 0){
                this.updateParams(updates);
            }
            
        }
        if (visible) schmedley.fade('in', this.el);
    },



    parseInnerParams: function(params) { }, 	// should be overridden


    updateParams: function(params, permanent) {
        if (this.noUpdate) return;
	
	if (permanent){
	    var pd = 1;
	}
	else {
	    var pd = 0;
	}
	
        var self = this;
	
        var req = new Request.JSON({
            url: "/updateParams.php", 'async': true, onComplete: function(response) {
                if (response && response.status == 'success') {
                }
                else {
                    schmedley.alert("Unable to update Params");
                }
                self.requests.erase(req);
            }
        });

        req.post({ t: this.dbID, p: JSON.encode(params), 'pd': pd }); // t for tabWidgetID
        this.requests.push(req);
    },
    

    removeParams: function(params) {
        var self = this;

        var req = new Request.JSON({
            url: "/removeParams.php", 'async': true, onComplete: function(response) {
                if (response && response.status == 'success') {
                }
                else {
                    schmedley.showError("Unable to Remove Params");
                }
                self.requests.erase(req);
            }
        });
        req.post({'t': this.dbID, 'p': JSON.encode(params)}); // t for tabWidgetID
    },


    requestEnc: function(cName, value, onComplete){
        var self = this;

        var url = "/requestEnc.php";
        var req = new Request.JSON({'url': url,
				    'async': true,
				    'onComplete': function(response) {
					if (response && response.status == 'success') {
					    self.storeEncData(cName, response.data.encValue, onComplete);
					}
					else {
					    schmedley.showError("There was an error dealing with the encryption of this data.  Cannot proceed.");
					}
					self.requests.erase(req);
				    }
                                   });
        req.send('v=' + value);
    },


    storeEncData: function(cName, value, onComplete){
        schmedley.storeInCookie(cName + '_' + this.dbID, value);
        onComplete.call(this, value);
    },

    getEncData: function(cName, promptMessage, isPass, onComplete, force){
        var cookieName = cName + '_' + this.dbID;

        var value = schmedley.getCookieValue(cookieName);
        var self = this;

        if (force || !value){
            this.prompt(promptMessage, isPass, function(value){
                self.requestEnc(cName, value, onComplete);
                return true;
            });
        }
        else {
            onComplete.call(this, value);
        }
    },

    prompt: function(promptMessage, isPass, onComplete){
        schmedley.blackOut('in');

        new Prompt(promptMessage, isPass, onComplete);
    },

    /**
        options
            label
            klass
            styles
    */
    createButton: function(options)
    {
        var button = new Element('div', {
            'class': options.klass
        })
            .set('html', '<div class="butl"></div><div class="butc">' + options.label + '</div><div class="butr"></div>')
            .setStyles(options.styles);

        return button;
    },

    savePosition: function(x, y){
        this.x = x;
        this.y = y;
    },

    createUploader: function(id) {
        if (!id){
	    var id = 'target_' + this.dbID;
        }

        var objs = $('objects');

	// look for an existing iframe
	var iframe = objs.getElementById(id);
	if (iframe) return iframe;

	// IE fucking sucks
        if (Browser.Engine.trident){
            var html = '<iframe name="' + id + '" src="" id="' + id + '" height=0 width=0 class="uploadObject">';
            var uploadObject = document.createElement(html); 
            objs.appendChild(uploadObject);
            return $(uploadObject);
        }
        else {
            var uploadObject = new Element('iframe');

            uploadObject.set({
                'id' : id,
                'name' : id,
                'src' : '',
                'class' : 'uploadObject'
            })
		.setStyles({'height': 0, 'width': 0})

        }

        uploadObject.inject($('objects'));
	return uploadObject;
    },

    //
    // options: 
    //   defaultURL: string, 
    //   submitHandler: Function, 
    //   errA: string, 
    //   errB, string,
    //   pickerHeading: string, 
    //   pickerPreview: boolean,
    //   fileTitle: string like photo, song, etc.
    //   urlHint: string, small text to help users understand what to put in the URL field
    //
    
    createUploadForm: function(fileDir, opts){
	if (!this.uploader) this.uploader = this.createUploader();

	var defaults = {defaultURL: '',
			submitHandler: function(){},
			deleteHandler: function() {}, // get passed to filepicker
			errorHandler: function(){},
			errA: gls('uplA'),
			errB: gls('uplB'),
			pickerHeading: gls('upl0'),
			pickerPreview: false,
			fileTitle: 'file',
			urlHint: gls('upl1'),
			container: schmedley.horizon,
			isLauncher: false,
			includeOuter: true,
			extensions: new Array(),
			sizeLimit: '10 MB'
		       };

	for(var i in defaults){
	    if ((typeof opts[i]) == 'undefined'){
		opts[i] = defaults[i];
	    }
	}

	if (fileDir.substring(fileDir.length - 1) != '/') fileDir += '/';

        // url input
        this.urlInput = new Element("input", {
            "type": "text",
            "class": "online",
            "value": opts.defaultURL
        })
            .setStyles({
		"height": "14px",
		"width": "240px",
		"margin-top": "7px"
	    });
	
        var self = this;

        new TextField(this.urlInput, null, null, function() {
	    self.uploadWait();

	    var url = self.urlInput.value;
	    if (!url.match(/^https?:\/\//)){
		url = 'http://' + url;
	    }

            opts.submitHandler({url: url});
        });
        
        // upload but 0
        this.uploadBut0 = new Element("div")
	    .addClass("butb")
	    .addClass("uploadBut0")
            .adopt(new Element('div', {"class": "butl"}))
            .adopt(new Element('div', {"class": "butc", "html": "Go"}))
            .adopt(new Element('div', {"class": "butr"}));

	var bw = this.uploadBut0.getFirst().getNext().clientWidth + 20;       // button width
	
       	this.uploadBut0.setStyle('left', ((264 - bw) / 2) + 'px');            // set button left
       	
       	this.uploadBut0.addEvent('click', function() {
	    var fileName = self.uploadEl.getElement('.uploadedFile').value;
	    if(fileName != '') {
		var extAllowed = true;

		// if extensions are defined make sure the file is one of them
		if (opts.extensions.length > 0){
		    extAllowed = false;
		    var ext = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();

		    for(var i = 0; i < opts.extensions.length; i++){
			if (opts.extensions[i].toLowerCase() == ext){
			    extAllowed = true;
			    break;
			}
		    }
		}

		if (!extAllowed){
		    alert("That file type is not allowed.");
		    return false;
		}

                var form = self.uploadEl.getElement('form.uploadForm');
		self.uploadWait();
		
		// when file finishes uploading
		self.uploader.addEvent('load', function() {
		    self.uploader.removeEvents('load');
		    // get url of newly uploaded image
		    req = new Request.JSON({
		    	url: '/lastUpload.php',
			onComplete: function(response) {
                            if (response
                                && response.status
                                && response.status == 'success'){
			        opts.submitHandler({url: response.data.url, metadata: response.data.metadata});	    
                            }
                            else {
                                alert(opts.errB + response.data.reason);
				opts.errorHandler({reason: response.data.reason});
                            }
                            
			}
		    }).get({'guid': self.guid});
		});

		form.submit();
	    }
	});
        
        // upload but 1
        this.uploadBut1 = new Element('div', {"class": "butb uploadBut1"})
            .adopt(new Element('div', {"class": "butl"}))
            .adopt(new Element('div', {"class": "butc", "html": "Go"}))
            .adopt(new Element('div', {"class": "butr"}));

        this.uploadBut1.addEvent('click', function(){
            new FilePicker(self.desk.dbID, fileDir, {onChoose: opts.submitHandler.bindWithEvent(self),
						     onDelete: opts.deleteHandler.bindWithEvent(self),
						     label: opts.pickerHeading,
						     showPreview: opts.pickerPreview
						    });
	});
	
       	this.uploadBut1.setStyle('left', ((264 - bw) / 2) + 'px');

        // upload but 2
        this.uploadBut2 = new Element("div", {"class": "butb uploadBut2"})
            .adopt(new Element("div", {"class": "butl"}))
            .adopt(new Element("div", {"class": "butc", "html": "Go"}))
            .adopt(new Element("div", {"class": "butr"}))
        
       	this.uploadBut2.setStyle('left', ((264 - bw) / 2) + 'px');

        this.uploadBut2.addEvent('mousedown', function(e) {
            this.setProperty('class', 'bdown');
        })
            .addEvent('mouseup', function() {
		this.setProperty('class', 'butb uploadBut2');
            })
            .addEvent('click', function() {
	    	if(self.urlInput.value)
		    opts.submitHandler({url: self.urlInput.value});
            });


        // launcher

	if (!this.uploadEl) {
	    this.uploadEl = new Element('div', {'class': 'fileUploader'})
		.setOpacity(0);
	    
	    if (opts.includeOuter){ // need a background like photos
		this.uploadOuter = new Element('div', {'class': 'fileUploaderOuter'})
		    .setStyles({'display': 'block'
			       })
		    .setOpacity(0);

		Draggable.init(this.uploadOuter, this.el);

		opts.container.adopt(this.uploadOuter
				     .adopt(this.uploadEl)
				    );
	    }
	    else { // inside the widget like music
		opts.container.adopt(this.uploadEl);
	    }
	}
        else {
	    this.uploadEl.empty();
	}
        
	this.uploadSpinner = new Element('img', {'class': "uploadSpinner",
						 'src': "/css/img/spinner-bt.gif" }
					);
	this.uploadEl.adopt(this.uploadSpinner);

	var formDiv = new Element('div', {'class': 'uploadFormDiv'});
	this.uploadEl.adopt(formDiv);

	self.guid = self.createGUID();
	
	//        schmedley.fade('in', self.uploadEl, null, this.uploadElFade);
	
	formDiv.adopt(new Element("h1", {
	    "html": "upload a new " + opts.fileTitle + ' <span style="font-size: 10px; font-style: italic; margin-left: 5px;">(' + opts.sizeLimit + ' max)</span>'
	}))
	    .adopt(new Element('form', {
	        "class": "uploadForm", 
		"action": "/upload.php",
		"method": "post",
		"enctype": "multipart/form-data",
		"encoding": "multipart/form-data", // IE needs this one
		"target": this.uploader.id
	    })
		   .addEvent('submit', function(){
		   })
     		   .setStyles({'margin': '0px', 'padding': '0px'})
		   .adopt(new Element('input', {type: 'hidden', name: 'fileDir', value: fileDir }))
		   .adopt(new Element('p').setStyles({
       		       "margin-top": "12px",
		       "margin-left": "7px"
		   })
			  .adopt(new Element("input", {
       			      "type": "file",
			      "class": "uploadedFile",
        		      "name": "uploadedFile"
			  })
				 .setStyles('width', '225px'))
			  .adopt(new Element('input', {
			      'type': 'hidden',
			      'name': 'guid',
			      'value': self.guid
			  }))
			  .adopt(new Element("div").setStyles({
       			      "margin-top": "10px",
          		      "margin-bottom": "5px"
			  })
				 .adopt(this.uploadBut0))))
	
	    .adopt(new Element('h1', {"html": "select a " + opts.fileTitle}).setStyle("margin-top", "70px"))
	    .adopt(new Element('p', {"html": "choose a " + opts.fileTitle + " already on your schmedley HD"})
		   .adopt(new Element('div')
			  .adopt(this.uploadBut1).setStyle("margin-top", "10px")
			 )
		  )
	    .adopt(new Element("h1", {"html": "enter a URL to an online " + opts.fileTitle}).setStyle("margin-top", "70px"))
	    .adopt(new Element("form").setStyles({'margin': '0px', 'padding': '0px'})
		   .adopt(new Element("p", {"html": opts.urlHint})
			  .adopt(this.urlInput)
			  .adopt(new Element("div")
				 .adopt(this.uploadBut2).setStyle("margin-top", "10px")
				)
			 )
		  );
	
	if (opts.isLauncher
	    && this.closeButton) {
	    var z = this.uploadEl.getStyle('z-index');
            this.closeButton.setStyles({'top': '4px', 'left': '295px', 'z-index': z++ });
	    
	}
	else {
	    
	}
	
	this.uploadUnWait();
	
	this.uploadEl.setStyles({
            'display': 'block'
	});
	
		// don't mess with this...
		if (Browser.Engine.webkit == true) {
        	this.el.getElement('input.uploadedFile').setStyle('color', '#fff');
		}

		// have to fade the uploadEl too, otherwise it doesn't end up visible
		// seems like a fade out is still in progress.

		schmedley.fade('in', this.uploadEl);

		if (opts.includeOuter){
		    schmedley.fade('in', this.uploadOuter);
		}
	
    },

    uploadWait: function() {
	this.uploadElFade = schmedley.fade('out', this.uploadEl.getElement('div.uploadFormDiv'));
	
	if (this.uploadSpinner) this.uploadSpinner.setStyle('display', 'block');
	
    },

    uploadUnWait: function(showForm) {
	if (this.uploadSpinner) this.uploadSpinner.setStyle('display', 'none');

	if (showForm) schmedley.fade('in', this.uploadEl.getElement('div.uploadFormDiv'));
    },

    moveToTab: function(tab){
	this.el.dispose();
	
	this.desk.widgets.erase(this);
	tab.desk.widgets[tab.desk.widgets.length] = this;

	this.desk = tab.desk;
	var self = this;

	// reset the event handlers
	this.el.removeEvents('mousedown');

	this.el.addEvent('mousedown', function(e) {
	    self.desk.widgetMouseDown(self);
	});

	var coords = this.desk.getOpenPosition(this.type);

	var x = coords[0] + 'px';
	var y = coords[1] + 'px';
	this.el.setStyles({'left': x, 'top': y});
	this.el.injectInside(this.desk.el);

	var req = new Request.JSON({
	    url: "/changeWidgetTab.php", 'async': true, onComplete: function(response) {
		if (response && response.status == 'success') {
		}
		else {
		    // not really critical so maybe don't need to do anything.
		    //                    schmedley.showError("Unable to Remove Params");
		}
		self.requests.erase(req);
	    }
	});
	req.post({'tw': this.dbID, 't': tab.dbID, 'x': x, 'y': y }); 

	this.desk.ZindexToTop(this);

    },

    // override as necessary
    dragStart: function(){
	this.desk.widgetMouseDown(this);
    },
    
    dragging: function(){
    },

    dragEnd: function(){
	this.desk.widgetMouseUp(this);
    },
    
    createGUID: function() {
	S4 = function() {return (((1+Math.random())*0x10000)|0).toString(16).substring(1);}
	return S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4();
    },

    cancelAll: function(e){
	var ev = new Event(e);

	//cancel any drags
	if (ev.key == 'esc'){
	    Draggable.finishEnd();
	}
    },

    /**
* should be considered abstract and defined in child classes
* @param {String} url the url of the deleted file
*/
    notifyDelete: function(url){
    }
    


    // don't leave any trailing commas
});


