diff --git a/apps/tasks/ajax/addtask.php b/apps/tasks/ajax/addtask.php
index 434fbc5fdd5ffd94ff130fc5e012dc7588601aff..81905666ff3c9ef88c8216ce76e4206c6d5fa25d 100644
--- a/apps/tasks/ajax/addtask.php
+++ b/apps/tasks/ajax/addtask.php
@@ -18,20 +18,19 @@ if( $calendar === false || $calendar['userid'] != OC_USER::getUser()){
 	exit();
 }
 
-$summary = $_POST['summary'];
-
-$vcalendar = new Sabre_VObject_Component('VCALENDAR');
-$vcalendar->add(new Sabre_VObject_Property('PRODID', 'ownCloud Calendar'));
-$vcalendar->add(new Sabre_VObject_Property('VERSION', '2.0'));
-$vtodo = new Sabre_VObject_Component('VTODO');
-$vtodo->add(new Sabre_VObject_Property('SUMMARY',$summary));
-$vtodo->add(new Sabre_VObject_Property('UID',OC_Calendar_Calendar::createUID()));
-$vcalendar->add($vtodo);
+$errors = OC_Task_VTodo::validateRequest($_POST, $l10n);
+if (!empty($errors)) {
+	echo json_encode( array( 'status' => 'error', 'data' => array( 'errors' => $errors )));
+	exit();
+}
+
+$vcalendar = OC_Task_VTodo::createVCalendarFromRequest($_POST);
 $id = OC_Calendar_Object::add($cid, $vcalendar->serialize());
 
-$details = OC_Contacts_Addressbook::structureContact($vtodo);
+$priority_options = OC_Task_VTodo::getPriorityOptions($l10n);
 $tmpl = new OC_Template('tasks','part.details');
-$tmpl->assign('details',$details);
+$tmpl->assign('priority_options', $priority_options);
+$tmpl->assign('details',$vcalendar->VTODO);
 $tmpl->assign('id',$id);
 $page = $tmpl->fetchPage();
 
diff --git a/apps/tasks/ajax/edittask.php b/apps/tasks/ajax/edittask.php
index f98bcf3f596d2da037ead1049168b47b37f278d2..9f836f1f8a84e3c4cd0e6def5352d924093ef0c3 100644
--- a/apps/tasks/ajax/edittask.php
+++ b/apps/tasks/ajax/edittask.php
@@ -24,23 +24,21 @@ if( $calendar === false || $calendar['userid'] != OC_USER::getUser()){
 	exit();
 }
 
-$summary = $_POST['summary'];
-
-$vtodo = Sabre_VObject_Reader::read($task['calendardata'])->VTODO[0];
-$uid = $vtodo->UID[0]->value;
-
-$vcalendar = new Sabre_VObject_Component('VCALENDAR');
-$vcalendar->add(new Sabre_VObject_Property('PRODID', 'ownCloud Calendar'));
-$vcalendar->add(new Sabre_VObject_Property('VERSION', '2.0'));
-$vtodo = new Sabre_VObject_Component('VTODO');
-$vtodo->add(new Sabre_VObject_Property('SUMMARY',$summary));
-$vtodo->add(new Sabre_VObject_Property('UID', $uid));
-$vcalendar->add($vtodo);
+$errors = OC_Task_VTodo::validateRequest($_POST, $l10n);
+if (!empty($errors)) {
+	echo json_encode( array( 'status' => 'error', 'data' => array( 'errors' => $errors )));
+	exit();
+}
+
+$vcalendar = Sabre_VObject_Reader::read($task['calendardata']);
+OC_Task_VTodo::updateVCalendarFromRequest($_POST, $vcalendar);
 OC_Calendar_Object::edit($id, $vcalendar->serialize());
 
+$priority_options = OC_Task_VTodo::getPriorityOptions($l10n);
 $tmpl = new OC_Template('tasks','part.details');
-$tmpl->assign('details',$vtodo);
-$tmpl->assign('id',$id);
+$tmpl->assign('priority_options', $priority_options);
+$tmpl->assign('details', $vcalendar->VTODO);
+$tmpl->assign('id', $id);
 $page = $tmpl->fetchPage();
 
 echo json_encode( array( 'status' => 'success', 'data' => array( 'id' => $id, 'page' => $page )));
diff --git a/apps/tasks/ajax/edittaskform.php b/apps/tasks/ajax/edittaskform.php
index 6cc7d2787cf38808c7389642595ee1c4930f6fbd..dc8bb60e64d142c2c99dbf8d210c49c4bf9dc99f 100644
--- a/apps/tasks/ajax/edittaskform.php
+++ b/apps/tasks/ajax/edittaskform.php
@@ -25,9 +25,23 @@ if( $calendar === false || $calendar['userid'] != OC_USER::getUser()){
 }
 
 $details = Sabre_VObject_Reader::read($task['calendardata'])->VTODO;
+$categories = array();
+if (isset($details->CATEGORIES)){
+	$categories = explode(',', $details->CATEGORIES->value);
+	$categories = array_map('trim', $categories);
+}
+
+$category_options = OC_Calendar_Object::getCategoryOptions($l10n);
+$percent_options = range(0, 100, 10);
+$priority_options = OC_Task_VTodo::getPriorityOptions($l10n);
+
 $tmpl = new OC_Template('tasks','part.edittaskform');
+$tmpl->assign('category_options', $category_options);
+$tmpl->assign('percent_options', $percent_options);
+$tmpl->assign('priority_options', $priority_options);
 $tmpl->assign('task',$task);
 $tmpl->assign('details',$details);
+$tmpl->assign('categories', $categories);
 $page = $tmpl->fetchPage();
 
 echo json_encode( array( 'status' => 'success', 'data' => array( 'page' => $page )));
diff --git a/apps/tasks/ajax/getdetails.php b/apps/tasks/ajax/getdetails.php
index d264aeab853d09bc22213c79ca795a976198d908..f111a399b365e174ee4e16fdb639d696ac3bac59 100644
--- a/apps/tasks/ajax/getdetails.php
+++ b/apps/tasks/ajax/getdetails.php
@@ -14,7 +14,10 @@ if( !OC_User::isLoggedIn()){
 $id = $_GET['id'];
 $task = OC_Calendar_Object::find($id);
 $details = Sabre_VObject_Reader::read($task['calendardata'])->VTODO;
+
+$priority_options = OC_Task_VTodo::getPriorityOptions($l10n);
 $tmpl = new OC_Template('tasks','part.details');
+$tmpl->assign('priority_options', $priority_options);
 $tmpl->assign('details',$details);
 $tmpl->assign('id',$id);
 $page = $tmpl->fetchPage();
diff --git a/apps/tasks/appinfo/app.php b/apps/tasks/appinfo/app.php
index 8bcc6085ec817d8bd7804dfe7e6e24e128693979..e94f991f734e1778133647667b646dc4e448f11c 100644
--- a/apps/tasks/appinfo/app.php
+++ b/apps/tasks/appinfo/app.php
@@ -1,6 +1,7 @@
 <?php
 $l=new OC_L10N('tasks');
 OC::$CLASSPATH['OC_Calendar_Calendar'] = 'apps/calendar/lib/calendar.php';
+OC::$CLASSPATH['OC_Task_VTodo'] = 'apps/tasks/lib/vtodo.php';
 
 OC_App::register( array(
   'order' => 11,
diff --git a/apps/tasks/js/tasks.js b/apps/tasks/js/tasks.js
index 528363f4237aee4d01760668079c65f214f5bf95..e145389a959779df10f4874097ea96f7ef6550e5 100644
--- a/apps/tasks/js/tasks.js
+++ b/apps/tasks/js/tasks.js
@@ -82,6 +82,14 @@ $(document).ready(function(){
 		return false;
 	});
 
+	$('#tasks_edittaskform #percent_complete').live('change',function(event){
+		if ($(event.target).val() == 100){
+			$('#tasks_edittaskform #complete').show();
+		}else{
+			$('#tasks_edittaskform #complete').hide();
+		}
+	});
+
 	$('#tasks_edittaskform input[type="submit"]').live('click',function(){
 		$.post('ajax/edittask.php',$('#tasks_edittaskform').serialize(),function(jsondata){
 			if(jsondata.status == 'success'){
@@ -89,7 +97,7 @@ $(document).ready(function(){
 				$('#task_details').html(jsondata.data.page);
 			}
 			else{
-				alert(jsondata.data.message);
+				alert(jsondata.data.errors);//TODO
 			}
 		}, 'json');
 		return false;
diff --git a/apps/tasks/lib/vtodo.php b/apps/tasks/lib/vtodo.php
new file mode 100644
index 0000000000000000000000000000000000000000..925ad77dea142ffadf89f1e135387d4024712a7a
--- /dev/null
+++ b/apps/tasks/lib/vtodo.php
@@ -0,0 +1,186 @@
+<?php
+/**
+ * ownCloud - Calendar
+ *
+ * @author Bart Visscher
+ * @copyright 2011 Bart Visscher bartv@thisnet.nl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * This class manages our calendars
+ */
+class OC_Task_VTodo extends OC_Calendar_Object{
+	public static function getPriorityOptions($l10n)
+	{
+		return array(
+			''  => $l10n->t('Unspecified'),
+			'1' => $l10n->t('1=highest'),
+			'2' => '2',
+			'3' => '3',
+			'4' => '4',
+			'5' => $l10n->t('5=medium'),
+			'6' => '6',
+			'7' => '7',
+			'8' => '8',
+			'9' => $l10n->t('9=lowest'),
+		);
+	}
+	public static function validateRequest($request, $l10n)
+	{
+		$errors = array();
+		if($request['summary'] == ''){
+			$errors['summary'] = $l10n->t('Empty Summary');
+		}
+
+		if(isset($request['categories']) && !is_array($request['categories'])){
+			$errors['categories'] = $l10n->t('Not an array');
+		}
+
+		try {
+			$timezone = OC_Preferences::getValue(OC_USER::getUser(), "calendar", "timezone", "Europe/London");
+			$timezone = new DateTimeZone($timezone);
+			new DateTime($request['due'], $timezone);
+		} catch (Exception $e) {
+			$errors['due'] = $l10n->t('Invalid date/time');
+		}
+
+		if ($request['percent_complete'] < 0 || $request['percent_complete'] > 100){
+			$errors['percent_complete'] = $l10n->t('Invalid percent complete');
+		}
+		if ($request['percent_complete'] == 100 && !empty($request['completed'])){
+			try {
+				$timezone = OC_Preferences::getValue(OC_USER::getUser(), "calendar", "timezone", "Europe/London");
+				$timezone = new DateTimeZone($timezone);
+				new DateTime($request['completed'], $timezone);
+			} catch (Exception $e) {
+				$errors['completed'] = $l10n->t('Invalid date/time');
+			}
+		}
+
+		$priority_options = OC_Task_VTodo::getPriorityOptions($l10n);
+		if (!in_array($request['priority'], array_keys($priority_options))) {
+			$errors['priority'] = $l10n->t('Invalid priority');
+		}
+		return $errors;
+	}
+
+	public static function createVCalendarFromRequest($request)
+	{
+		$vcalendar = new Sabre_VObject_Component('VCALENDAR');
+		$vcalendar->add('PRODID', 'ownCloud Calendar');
+		$vcalendar->add('VERSION', '2.0');
+
+		$now = new DateTime();
+
+		$vtodo = new Sabre_VObject_Component('VTODO');
+		$vcalendar->add($vtodo);
+
+		$created = new Sabre_VObject_Element_DateTime('CREATED');
+		$created->setDateTime($now, Sabre_VObject_Element_DateTime::UTC);
+		$vtodo->add($created);
+
+		$uid = self::createUID();
+		$vtodo->add('UID',$uid);
+
+		return self::updateVCalendarFromRequest($request, $vcalendar);
+	}
+
+	public static function updateVCalendarFromRequest($request, $vcalendar)
+	{
+		$summary = $request['summary'];
+		$categories = $request['categories'];
+		$priority = $request['priority'];
+		$percent_complete = $request['percent_complete'];
+		$completed = $request['completed'];
+		$location = $request['location'];
+		$due = $request['due'];
+		$description = $request['description'];
+
+		$now = new DateTime();
+		$vtodo = $vcalendar->VTODO[0];
+
+		$last_modified = new Sabre_VObject_Element_DateTime('LAST-MODIFIED');
+		$last_modified->setDateTime($now, Sabre_VObject_Element_DateTime::UTC);
+		$vtodo->__set('LAST-MODIFIED', $last_modified);
+
+		$dtstamp = new Sabre_VObject_Element_DateTime('DTSTAMP');
+		$dtstamp->setDateTime($now, Sabre_VObject_Element_DateTime::UTC);
+		$vtodo->DTSTAMP = $dtstamp;
+
+		$vtodo->SUMMARY = $summary;
+
+		if ($location != '') {
+			$vtodo->LOCATION = $location;
+		}else{
+			unset($vtodo->LOCATION);
+		}
+
+		if ($categories != '') {
+			$vtodo->CATEGORIES = join(',',$categories);
+		}else{
+			unset($vtodo->CATEGORIES);
+		}
+
+		if ($priority != '') {
+			$vtodo->PRIORITY = $priority;
+		}else{
+			unset($vtodo->PRIORITY);
+		}
+
+		if ($description != '') {
+			$vtodo->DESCRIPTION = $description;
+		}else{
+			unset($vtodo->DESCRIPTION);
+		}
+
+		if ($due) {
+			$due_property = new Sabre_VObject_Element_DateTime('DUE');
+			$timezone = OC_Preferences::getValue(OC_USER::getUser(), "calendar", "timezone", "Europe/London");
+			$timezone = new DateTimeZone($timezone);
+			$due_property->setDateTime(new DateTime($due, $timezone));
+			$vtodo->DUE = $due_property;
+		} else {
+			unset($vtodo->DUE);
+		}
+
+		if (!empty($percent_complete)) {
+			$vtodo->__set('PERCENT-COMPLETE', $percent_complete);
+		}else{
+			$vtodo->__unset('PERCENT-COMPLETE');
+		}
+
+		if ($percent_complete == 100){
+			if (!$completed){
+				$completed = 'now';
+			}
+		} else {
+			$completed = null;
+		}
+		if ($completed) {
+			$completed_property = new Sabre_VObject_Element_DateTime('COMPLETED');
+			$timezone = OC_Preferences::getValue(OC_USER::getUser(), "calendar", "timezone", "Europe/London");
+			$timezone = new DateTimeZone($timezone);
+			$completed_property->setDateTime(new DateTime($completed, $timezone));
+			$vtodo->COMPLETED = $completed_property;
+		} else {
+			unset($vtodo->COMPLETED);
+		}
+
+		return $vcalendar;
+	}
+}
+
diff --git a/apps/tasks/templates/part.details.php b/apps/tasks/templates/part.details.php
index 574f4c6b8e499f57ea6494dd8a5f997173d37fc9..a6561d97be9b1db809ae3512a44e019c78995e3d 100644
--- a/apps/tasks/templates/part.details.php
+++ b/apps/tasks/templates/part.details.php
@@ -1,9 +1,42 @@
 <?php if(isset($_['details']->SUMMARY)): ?>
 <table>
-<?php echo $this->inc('part.property', array('label' => $l->t('Summary'), 'property' => $_['details']->SUMMARY)); ?>
+<?php
+echo $this->inc('part.property', array('label' => $l->t('Summary'), 'property' => $_['details']->SUMMARY));
+if(isset($_['details']->LOCATION)):
+	echo $this->inc('part.property', array('label' => $l->t('Location'), 'property' => $_['details']->LOCATION));
+endif;
+if(isset($_['details']->CATEGORIES)):
+	echo $this->inc('part.property', array('label' => $l->t('Categories'), 'property' => $_['details']->CATEGORIES));
+endif;
+if(isset($_['details']->DUE)):
+	echo $this->inc('part.property', array('label' => $l->t('Due'), 'property' => $_['details']->DUE[0]));
+endif;
+if(isset($_['details']->PRIORITY)):
+	echo $this->inc('part.property', array('label' => $l->t('Priority'), 'property' => $_['details']->PRIORITY[0], 'options' => $_['priority_options']));
+endif;
+if($_['details']->__isset('PERCENT-COMPLETE') || isset($_['details']->COMPLETED)):
+?>
+<tr>
+	<th>
+		<?php echo $l->t('Complete') ?>
+	</th>
+	<td>
+<?php if($_['details']->__isset('PERCENT-COMPLETE')):
+		echo $_['details']->__get('PERCENT-COMPLETE')->value.' % ';
+	endif;
+	if(isset($_['details']->COMPLETED)):
+		echo $l->t('on '). $l->l('datetime', $_['details']->COMPLETED[0]->getDateTime());
+	endif;
+	echo '</tr>';
+endif;
+if(isset($_['details']->DESCRIPTION)):
+	echo $this->inc('part.property', array('label' => $l->t('Description'), 'property' => $_['details']->DESCRIPTION));
+endif; ?>
 </table>
 <form>
 	<input type="button" id="tasks_delete" value="<?php echo $l->t('Delete');?>">
 	<input type="button" id="tasks_edit" value="<?php echo $l->t('Edit');?>">
 </form>
+<?php else: ?>
+<?php var_dump($_['details']); ?>
 <?php endif ?>
diff --git a/apps/tasks/templates/part.property.php b/apps/tasks/templates/part.property.php
index 68acd68954cf6b36d6799f510fe0c7513a1fb1ff..591fd363e6f62c02d8f5d2fc2087fd2c6b4d9802 100644
--- a/apps/tasks/templates/part.property.php
+++ b/apps/tasks/templates/part.property.php
@@ -3,6 +3,20 @@
 		<?php echo $_['label'] ?>
 	</th>
 	<td>
-		<?php echo $_['property']->value ?>
+		<?php
+			switch (get_class($_['property']))
+			{
+				case 'Sabre_VObject_Element_DateTime':
+					echo $l->l('datetime', $_['property']->getDateTime());
+					break;
+				default:
+					$value = $_['property']->value;
+					if (isset($_['options']))
+					{
+						$value = $_['options'][$value];
+					}
+					echo nl2br($value);
+			}
+		?>
 	</td>
 </tr>
diff --git a/apps/tasks/templates/part.taskform.php b/apps/tasks/templates/part.taskform.php
index 8fe917c946613e3d8a05eff52a49f5469acc42cb..139693c0e96e9e2c67272df3dbc0283264fd8617 100644
--- a/apps/tasks/templates/part.taskform.php
+++ b/apps/tasks/templates/part.taskform.php
@@ -1,2 +1,42 @@
 	<label for="summary"><?php echo $l->t('Summary'); ?></label>
-	<input type="text" id="summary" name="summary" value="<?php echo isset($_['details']->SUMMARY) ? $_['details']->SUMMARY[0]->value : '' ?>"><br>
+	<input type="text" id="summary" name="summary" placeholder="<?php echo $l->t('Summary of the task');?>" value="<?php echo isset($_['details']->SUMMARY) ? $_['details']->SUMMARY[0]->value : '' ?>">
+	<br>
+	<label for="location"><?php echo $l->t('Location'); ?></label>
+	<input type="text" id="location" name="location" placeholder="<?php echo $l->t('Location of the task');?>" value="<?php echo isset($_['details']->LOCATION) ? $_['details']->LOCATION[0]->value : '' ?>">
+	<br>
+	<label for="categories"><?php echo $l->t('Categories'); ?></label>
+	<select name="categories[]" multiple="multiple">
+		<?php
+var_dump($_['categories']);
+		foreach($_['category_options'] as $category){
+			echo '<option value="' . $category . '"' . (in_array($category, $_['categories']) ? ' selected="selected"' : '') . '>' . $category . '</option>';
+		}
+		?>
+	</select>
+	<br>
+	<label for="due"><?php echo $l->t('Due'); ?></label>
+	<input type="text" id="due" name="due" placeholder="<?php echo $l->t('Due date') ?>" value="<?php echo isset($_['details']->DUE) ? $l->l('datetime', $_['details']->DUE[0]->getDateTime()) : '' ?>">
+	<br>
+	<select name="percent_complete" id="percent_complete">
+		<?php
+		foreach($_['percent_options'] as $percent){
+			echo '<option value="' . $percent . '"' . (($_['details']->__get('PERCENT-COMPLETE') && $percent == $_['details']->__get('PERCENT-COMPLETE')->value) ? ' selected="selected"' : '') . '>' . $percent . ' %</option>';
+		}
+		?>
+	</select>
+	<label for="percent_complete"><?php echo $l->t('Complete'); ?></label>
+	<span id="complete"<?php echo ($_['details']->__get('PERCENT-COMPLETE') && $_['details']->__get('PERCENT-COMPLETE')->value == 100) ? '' : ' style="display:none;"' ?>><label for="completed"><?php echo $l->t('completed on'); ?></label>
+	<input type="text" id="completed" name="completed" value="<?php echo isset($_['details']->COMPLETED) ? $l->l('datetime', $_['details']->COMPLETED[0]->getDateTime()) : '' ?>"></span>
+	<br>
+	<label for="priority"><?php echo $l->t('Priority'); ?></label>
+	<select name="priority">
+		<?php
+		foreach($_['priority_options'] as $priority => $label){
+			echo '<option value="' . $priority . '"' . ((isset($_['details']->PRIORITY) && $priority == $_['details']->PRIORITY->value) ? ' selected="selected"' : '') . '>' . $label . '</option>';
+		}
+		?>
+	</select>
+	<br>
+	<label for="description"><?php echo $l->t('Description'); ?></label><br>
+	<textarea placeholder="<?php echo $l->t('Description of the task');?>" name="description"><?php echo isset($_['details']->DESCRIPTION) ? $_['details']->DESCRIPTION[0]->value : '' ?></textarea>
+	<br>