    var tagListTemplate;
    var tagSelecterTemplate;
    var commentListTemplate;
    var linkedTaskListTemplate;
    var linkedTaskTagSelecterTemplate;
	function init() {
	    var ajp = new AjaxPages();
	    ajp.load("ajp/TaskDetailTagList.ajp");
	    tagListTemplate = ajp.getProcessor();
	    
	    ajp.load("ajp/TaskDetailTagSelecter.ajb");
	    tagSelecterTemplate = ajp.getProcessor();
	    
	    ajp.load("ajp/TaskDetailCommentList.ajp");
	    commentListTemplate = ajp.getProcessor();
	    
	    ajp.load("ajp/TaskDetailLinkedTaskList.ajp");
	    linkedTaskListTemplate = ajp.getProcessor();

	    ajp.load("ajp/TaskDetailLinkedTaskTagSelecter.ajb");
	    linkedTaskTagSelecterTemplate = ajp.getProcessor();
	}
	/**
	 * Refresh task data
	 */
	function update(varTask, varTagMasterList) {
		$('updateDate').innerHTML = varTask.updateDate;
		$('contents').value = varTask.contents;
		$('contents').defaultValue = varTask.contents;
		$('estimatedManHour').value = varTask.estimatedManHour;
		$('estimatedManHour').defaultValue = varTask.estimatedManHour;
		if (varTagMasterList) {
		    $('tagSelecter').innerHTML = tagSelecterTemplate({task:varTask, tagMasterList:varTagMasterList});
		    updateLinkedTask(varTagMasterList);
		}
	}
	
	function updateLinkedTask(varTagMasterList) {
	    $('linkedTaskTagSelecter').innerHTML = linkedTaskTagSelecterTemplate({tagMasterList:varTagMasterList});
	}
	/**
	 * Change task's status.
	 */
	function updateStatus(targetTaskId, updateStatusId) {
		ajaxUpdateStatus(targetTaskId, updateStatusId, handleUpdateStatusResult);
	}
	function handleUpdateStatusResult(result, request) {
		$('statusIcon').src = 'resources/skin/default/image/icon/' + result.task.status.icon.large;
		update(result.task);
	}
	/**
	 * Open task's tag editor.
	 */
	function openTagListForm() {
		Element.hide('tagListViewContainer');
		Element.hide('tagListLink');
		Element.show('tagListFormContainer');
		$('tagList').focus();
	}
	function closeTagListForm() {
		Element.show('tagListViewContainer');
		Element.show('tagListLink');
		Element.hide('tagListFormContainer');
	}
	function editTagList() {
		var taskId = $F('tagListTaskId');
		var tagList = $F('tagList');
		ajaxEditTagList(taskId, tagList, handleEditTagResult);
		closeTagListForm();
		return false;
	}
	function handleEditTagResult(result, request) {
	    $('tagListView').innerHTML = tagListTemplate({task:result.task});
		var tmpTags = $AX(result.task.tagList.tag);
		var tagList = tmpTags.collect(
					function (value, index) {
						return value.name.formatWSTag();
					});
		$('tagList').value = tagList.join('');
		$('tagList').defaultValue = tagList.join('');
		
		update(result.task, result.tagMasterList);
	}
	/**
	 * Open task contents editor
	 */
	function openEditContentsForm() {
		Element.hide('contentsView');
		Element.hide('editContentsLink');
		Element.show('editContentsForm');
		$('contents').focus();
	}
	function closeEditContentsForm() {
		Element.hide('editContentsForm');
		Element.show('contentsView');
		Element.show('editContentsLink');
	}
	function editContents() {
		ajaxEditContents($F('contentsTaskId'), $F('contents'), handleEditContentsResult);
		return false;
	}
	function handleEditContentsResult(result, request) {
		$('contentsView').innerHTML = result.task.contents.formatSimpleHTML();
		
		closeEditContentsForm();
		update(result.task);
	}
	function deleteFile(fileId, elementId) {
		ajaxDeleteFile(fileId, elementId, handleDeleteFileResult);
	}
	function handleDeleteFileResult(result, request) {
		Element.remove(request.element);
	}
	function openUploadFileForm() {
		Element.hide('uploadFileLink');
		Element.show('uploadFileForm');
	}
	function closeUploadFileForm() {
		Element.show('uploadFileLink');
		Element.hide('uploadFileForm');
	}
	/**
	 * Open comment editor.
	 */
	function openCommentForm() {
		Element.hide('addCommentLink');
		Element.show('CommentForm');
		$('commentator').value = '';
		$('comment').value = '';
		$('comment').focus();
	}
	function closeCommentForm() {
		Element.show('addCommentLink');
		Element.hide('CommentForm');
	}
	function addComment() {
		ajaxAddComment($F('commentTaskId'), $F('commentator'), $F('comment'), handleAddCommentResult);
		return false;
	}
	function handleAddCommentResult(result, request) {
		Element.show('commentList');
	    $('commentList').innerHTML = commentListTemplate({task:result.task});
		update(result.task);
		
		closeCommentForm();
	}
	/**
	 * Open esimated man hour editor.
	 */
	function openEstimatedManHourForm() {
		Element.hide('estimatedManHourContainer');
		Element.hide('estimatedManHourLink');
		Element.show('estimatedManHourForm');
		Element.show('estimatedManHourFormButton');
		$('estimatedManHour').focus();
	}
	function closeEstimatedManHourForm() {
		Element.show('estimatedManHourContainer');
		Element.show('estimatedManHourLink');
		Element.hide('estimatedManHourForm');
		Element.hide('estimatedManHourFormButton');
	}
	function editEstimatedManHour() {
		ajaxEditEstimatedManHour($F('estimatedManHourTaskId'), $F('estimatedManHour'), handleEstimatedManHourResult);
		return false;
	}
	function handleEstimatedManHourResult(result, request) {
		$('estimatedManHourView').innerHTML = result.task.estimatedManHour;
		update(result.task);
		
		closeEstimatedManHourForm();
	}
	/// Linked Task /////////////////////////////////////////////////
	function updateLinkedTaskStatus(targetTaskId, updateStatusId) {
		ajaxUpdateStatus(targetTaskId, updateStatusId, handleUpdateLinkedTaskStatusResult);
	}
	function handleUpdateLinkedTaskStatusResult(result, request) {
		var elementId = 'linkedTaskStatusIcon-' + request.taskId;
		$(elementId).src = 'resources/skin/default/image/icon/' + result.task.status.icon.middle;
		$('linkedTaskUpdateDate-' + request.taskId).innerHTML = result.task.updateDate;
	}
	function deleteLinkedTask(targetTaskId, elementId) {
		ajaxDeleteTask(targetTaskId, elementId, handleDeleteLinkedTaskResult);
	}
	function handleDeleteLinkedTaskResult(result, request) {
		Element.remove(request.element);
	}
	/**
	 * Unlink task. This doesn't delete task, just unlink.
	 */
	function unlinkTask(fromTaskId, toTaskId, elementId) {
		ajaxUnlinkTask(fromTaskId, toTaskId, elementId, handleUnlinkTaskResult);
	}
	function handleUnlinkTaskResult(result, request) {
		Element.remove(request.element);
	}
	/**
	 * open new linked task editor.
	 */
	function openLinkedTaskForm() {
		Element.hide('addLinkedTaskLink');
		Element.show('LinkedTaskForm');
		$('LinkedTaskForm').reset();
		$('linkedTaskTagList').focus();
	}
	function closeLinkedTaskForm() {
		Element.show('addLinkedTaskLink');
		Element.hide('LinkedTaskForm');
	}
	function addLinkedTask() {
		ajaxAddLinkedTask(
			$F('parentTaskId'), 
			$F('linkedTaskContents'), 
			$F('linkedTaskTagList'), 
			handleAddLinkedTaskResult);
		return false;
	}
	function handleAddLinkedTaskResult(result, request) {
		var row = linkedTaskListTemplate({task:result.task, parentTaskId:123});
		new Insertion.Bottom($('linkedTaskList'), row);
		closeLinkedTaskForm();
		updateLinkedTask(result.tagMasterList);
		Element.show('linkedTaskList');
	}
