function File(file_id, filename, public_link, private_link, object_key, creation_date_ansi, updated_date_ansi, creation_date_pretty, creation_time_pretty, updated_date_pretty, updated_time_pretty, size, isPrivate, description, descriptionHtml, tags, public_only) {
    this.file_id = file_id;
    this.filename = filename;
    this.public_link = public_link;
    this.private_link = private_link;
    this.object_key = object_key;
    this.creation_date_ansi = creation_date_ansi;
    this.updated_date_ansi = updated_date_ansi;
    this.creation_date_pretty = creation_date_pretty;
    this.creation_time_pretty = creation_time_pretty;
    this.updated_date_pretty = updated_date_pretty;
    this.updated_time_pretty = updated_time_pretty;
    this.size = size;

    if (size/1024>700)
	this.size_pretty = Math.round(size/(1024*1024)*100)/100 + ' MB';
    else
	this.size_pretty = Math.round((10*size)/1024)/10 + ' KB';
	

    this.isPrivate = isPrivate;
    this.description = description;
    this.descriptionHtml = descriptionHtml;
    this.tags = tags;
    this.public_only = (public_only==0 ? false : true);

    this.selected = false;
    this.editFilename = false;
    this.editTags = false;
    this.editDescription = false;
    this.deleteConfirm = false;

    this.updated = true;

    return(this);
};



var Filetree = {
    container: null,
    tree: new Object(),
    sorting: new Array(),

    init: function(container){
	Filetree.container = container;
    },

    populate: function(){
	var odd = true;
	var total_size = 0;
	var total_files = 0;

	var selectObject = null;
	var selectObjectValue = null;
	for (file_id in Filetree.tree) {
	    var file = Filetree.tree[file_id];
	    if ( $(file_id) ) {
		var root = $(file_id);
	    } else {
		var root = document.createElement('div');
		root.setAttribute('id', file_id);
		root.setAttribute('rel', 'treeitem');
		Filetree.container.appendChild(root);
	    }

	    if (!file) {
		root.style.display = 'none';
		continue;
	    }

	    if (file.selected)
		root.className = 'selected';
	    else 
		root.className = (odd ? 'odd' : 'even');


	    if (file.selected || file.updated) {
		root.onclick = function(e) {
		    Filetree.select(this.id);
		}
		
		var html = '';
		
		if (!file.public_only) {
		    // Links
		    html+='<div style="float:right;">';
		    
		    //Delete
		    if (!file.deleteConfirm)
			html+=' <a href="javascript:void(0)" onclick="S3action.deleteConfirm('+file_id+', true)"><img alt="Delete file"  src="/resources/s3/delete.gif"></a> ';
		    else
			html+=' <span class="action">Delete this file?</span> <a href="javascript:void(0)" onclick="S3action.deleteFile('+file_id+')">Yes</a> / <a href="javascript:void(0)" onclick="S3action.deleteConfirm('+file_id+', false)">No</a>';
		    
		    html+='</div>';
		    
		    // Private
		    if (file.isPrivate) 
			html+=' <a href="javascript:void(0)" onclick="S3action.setPublic('+file_id+')"><img alt="Private - Click to make public" src="/resources/s3/private.gif" style="padding-right:5px;"></a>';
		    else
			html+=' <a href="javascript:void(0)" onclick="S3action.setPrivate('+file_id+')"><img alt="Public - Click to make private" src="/resources/s3/public.gif" style="padding-right:5px;"></a>';
		}
		
		// Filename
		if (!file.editFilename) {
		    html+='<span id="_filename_'+file_id+'"><a class="filename" href="'+(file.isPrivate?file.private_link:file.public_link)+'" !onclick="location.href=\''+(file.isPrivate?file.private_link:file.public_link)+'\';">'+file.filename+'</a> ';
		    if (file.selected) {
			html+=' &nbsp; &nbsp; <a class="action" href="javascript:void(0)" onclick="S3action.editFilename('+file_id+');">Rename</a>';
		    }
		    html+='</span>';
		} else {
		    html+='<span id="_editfilename_'+file_id+'"><form id="_editfilename_form_'+file_id+'" style="display:inline; margin:0;" onsubmit="S3action.setFilename('+file_id+',this.filename.value); return(false);" $(\'_editfilename_input_'+file_id+'\').value);"><input id="_editfilename_input_'+file_id+'" type="text" class="text" name="filename" value="'+file.filename+'" onclick="event.cancelBubble=true;" size="30" style="padding:1px; font-size:10px;"> <a class="action" href="javascript:void(0)" onclick="S3action.setFilename('+file_id+', $(\'_editfilename_input_'+file_id+'\').value);">Save</a></form></span>';
		    selectObject = '_editfilename_input_'+file_id;
		}
		
		// Tags
		if (file.tags.length>0 || file.selected) {
		    html+='<div id="_tags_'+file_id+'">';
		    if (file.public_only) {
			html+='<span class="smallupper">Tags</span>';
		    } else {
			html+='<a class="smallupper" href="javascript:void(0)" onclick="S3action.editTags('+file_id+')">Tags</a>';
		    }
		    if (file.selected && !file.editTags) 
			html+=' <span id="__addtags_link_'+file_id+'" class="smallupper">(<a class="action" href="javascript:void(0)" onclick="S3action.editTags('+file_id+')">+</a>)</span>';
		    
		    html+='<span class="smallupper">:&nbsp;</span>';
		}
		
		if (file.tags.length>0) {
		    for (var i=0; i<file.tags.length; i++) {
			html+='<a class="tag" rel="tag" href="javascript:void(0)" onclick="S3action.showTag(\''+file.tags[i]+'\')">'+file.tags[i]+'</a>&nbsp; ';
			if (file.selected) 
			    html+='<a class="delete" href="javascript:void(0)" onclick="S3action.deleteTag('+file_id+',\''+file.tags[i]+'\');">x</a> &nbsp; ';
		    }
		} else {
		    if (file.selected) {
			html+='<span class="discrete">None</span>';
		    }
		}
		
		if (file.editTags && file.selected) {
		    html+='<div id="_addtags_'+file_id+'" style="margin-left:30px;"><form id="_addtags_form_'+file_id+'" style="margin:0;" onsubmit="S3action.setTags('+file_id+',this.tags.value); return(false);"><input id="_addtags_input_'+file_id+'" type="text" class="text" name="tags" onclick="event.cancelBubble=true;" size="30" style="padding:1px; font-size:10px;"> <a class="action" href="javascript:void(0)" onclick="S3action.setTags('+file_id+', $(\'_addtags_input_'+file_id+'\').value);">Add tag(s)</a></form></div>';
		    selectObject = '_addtags_input_'+file_id;
		}
		
		if (file.tags.length>0 || file.selected) {
		    html+='</div>';
		}
		
		
		// Description
		if (file.description.length || file.selected) {
		    html+='<div id="_desc_'+file_id+'">';
		    if (file.public_only) {
			html+='<span class="smallupper">Desc</span>';
		    } else {
			html+='<a class="smallupper" href="javascript:void(0)" onclick="S3action.editDescription('+file_id+')">Desc</a>';
		    }
		    if (file.selected && !file.editDescription) 
			html+=' <span id="__editdesc_link_'+file_id+'" class="smallupper">(<a class="action" href="javascript:void(0)" onclick="S3action.editDescription('+file_id+')">+</a>)</span>';
		    
		    html+='<span class="smallupper">:&nbsp;</span>';
		}
		
		if (file.editDescription && file.selected) {
		    html+='<div id="_addtags_'+file_id+'"><textarea id="_editdesc_ta_'+file_id+'" class="text" name="description" onclick="event.cancelBubble=true;" style="font-size:10px; width:95%;"></textarea><br/><a class="action" href="javascript:void(0)" onclick="S3action.setDescription('+file_id+', $(\'_editdesc_ta_'+file_id+'\').value);">Save description</a></div>';
		    selectObject = '_editdesc_ta_'+file_id;
		    selectObjectValue = file.description;
		} else {
		    if (file.selected) {
			if (file.description.length) {
			    html+='<div style="display:inline;" id="_labeldesc_'+file_id+'" class="discrete">'+file.descriptionHtml+'</div>';
			} else {
			    html+='<div style="display:inline;" id="_labeldesc_'+file_id+'" class="discrete">None</div>';
			} 
		    } else {
			if (file.description.length) {
			    html+='<div style="display:inline;" id="_labeldesc_'+file_id+'" class="discrete">'+file.descriptionHtml+'</div>';
			}
		    }
		}
		
		if (file.description.length || file.selected)
		    html+='</div>'
			
			
			
			if (file.selected) {
			    html+='<div id="_meta_'+file_id+'"><span class="smallupper">Meta:</span> <span class="discrete">';
			    html+='Uploaded: ' + file.creation_date_pretty + ' &middot; Size: ' + file.size_pretty;
			    if (!file.isPrivate) 
				html+=' &middot; <a class="discrete" href="'+file.public_link+'?torrent" onclick="location.href=\''+file.public_link+'?torrent\';">Download as torrent</a>';
			    html+='</span></div>';
			}
		
		// Set the HTML
		root.innerHTML = html;
	    }


	    //
	    file.updated = false;

	    total_files++;
	    total_size+=file.size;
	    odd = !odd;
	}

	$('indicator').style.display = 'none';
	if (total_files==0)
   	   $('nofiles').style.display = '';
        else
   	   $('nofiles').style.display = 'none';

	if (selectObject) {
	   Field.select(selectObject);
	   if (selectObjectValue) $(selectObject).value = selectObjectValue;
	}

	if (total_files>0) {
	    $('sum').style.display = '';
	    $('sum_files').innerHTML = total_files + ' files';


	    if (total_size/1024>700)
		var total_size_pretty = Math.round(total_size/(1024*1024)*100)/100 + ' MB';
	    else
		var total_size_pretty = Math.round((10*total_size)/1024)/10 + ' KB';
	    $('sum_size').innerHTML = total_size_pretty;
	} else {
	    $('sum').style.display = 'none';
	}
    },

    select: function(file_id){
	for (id in Filetree.tree) {
	    var file = Filetree.tree[id];
	    if (id!=file_id && Filetree.tree[id] && Filetree.tree[id].selected) {
		Filetree.tree[id].selected = false;
		Filetree.tree[id].updated = true;
		Filetree.tree[id].deleteConfirm = false;
		Filetree.tree[id].editDescription = false;
	    }
	}

	if (file_id && Filetree.tree[file_id]) {
	    if (!Filetree.tree[file_id].public_only) {
		Filetree.tree[file_id].selected = true;
		Filetree.populate();
	    }
	}
    },

    clear: function(){
	Filetree.tree = new Object();
	Filetree.clearContainer();
    },

    clearContainer: function(){
	$('indicator').style.display = '';
        $('sum').style.display = 'none';
	Filetree.container.innerHTML = '';
    },

    appendXML: function(xml, position){
	var f = Filetree;
	var files = xml.documentElement.getElementsByTagName('file');
	for (var i=0; files[i]; i++) {
	    var n = files[i];
	    
	    var file_id = new Number(n.getAttribute('file_id'));
	    var filename = n.getAttribute('filename');
	    var public_link = n.getAttribute('public_link');
	    var private_link = n.getAttribute('private_link');
	    var object_key = n.getAttribute('object_key');
	    var creation_date_ansi = n.getAttribute('creation_date_ansi');
	    var updated_date_ansi = n.getAttribute('updated_date_ansi');
	    var creation_date_pretty = n.getAttribute('creation_date_pretty');
	    var creation_time_pretty = n.getAttribute('creation_time_pretty');
	    var updated_date_pretty = n.getAttribute('updated_date_pretty');
	    var updated_time_pretty = n.getAttribute('updated_time_pretty');
	    var size = new Number(n.getAttribute('size'));
	    var isPrivate = (n.getAttribute('private')==1 ? true : false);
	    var description = (n.getElementsByTagName('description')[0].firstChild ? n.getElementsByTagName('description')[0].firstChild.nodeValue : '');
	    var descriptionHtml = (n.getElementsByTagName('descriptionhtml')[0].firstChild ? n.getElementsByTagName('descriptionhtml')[0].firstChild.nodeValue : '');

	    var tags = new Object();
	    tags.length = 0;
	    var tagsNodes = n.getElementsByTagName('tag');
	    for (var ix=0; tagsNodes[ix]; ix++) {
		if (!tagsNodes[ix].firstChild) {break;}
    		tags[ix] = tagsNodes[ix].firstChild.nodeValue;
		tags.length++;
	    }
	    var public_only = n.getAttribute('public_only');
	    
	    f.tree[file_id] = new File(file_id, filename, public_link, private_link, object_key, creation_date_ansi, updated_date_ansi, creation_date_pretty, creation_time_pretty, updated_date_pretty, updated_time_pretty, size, isPrivate, description, descriptionHtml, tags, public_only);
	}

	Filetree.populate();
    },

    remove: function(id){
	var f = Filetree;
	f.tree[id] = null;
	
	Filetree.populate();
    },

    removeTag: function(file_id, tag){
	var file = Filetree.tree[file_id];
	var cur = file.tags;

	var next = new Object();
	var i = 0;
	next.length = 0;
	for (var ix=0; ix<cur.length; ix++) {
            if (cur[ix]!=tag) {
		next[i] = cur[ix];
		i++;
		next.length++;
	    }
	}
	Filetree.tree[file_id].tags = next;
	
	Filetree.populate();
    },

    appendXMLFromUrl: function(url, params){
	new Ajax.Request(url, {method:'post',postBody:params,onComplete:function(originalRequest){Filetree.appendXML(originalRequest.responseXML);}});
    }
}
