public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as TimeEntry;
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.WriteIdIfNotNull(entity.Issue, RedmineKeys.ISSUE_ID);
                result.WriteIdIfNotNull(entity.Project, RedmineKeys.PROJECT_ID);
                result.WriteIdIfNotNull(entity.Activity, RedmineKeys.ACTIVITY_ID);
               
                if (!entity.SpentOn.HasValue) entity.SpentOn = DateTime.Now;

                result.WriteDateOrEmpty(entity.SpentOn, RedmineKeys.SPENT_ON);
                result.Add(RedmineKeys.HOURS, entity.Hours);
                result.Add(RedmineKeys.COMMENTS, entity.Comments);
                result.WriteArray(RedmineKeys.CUSTOM_FIELDS, entity.CustomFields, new IssueCustomFieldConverter(), serializer);

                var root = new Dictionary<string, object>();
                root[RedmineKeys.TIME_ENTRY] = result;
                return root;
            }

            return result;
        }
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as TimeEntry;
            var root = new Dictionary<string, object>();
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.WriteIdIfNotNull(entity.Issue, "issue_id");
                result.WriteIdIfNotNull(entity.Project, "project_id");
                result.WriteIdIfNotNull(entity.Activity, "activity_id");
                if (!entity.SpentOn.HasValue) entity.SpentOn = DateTime.Now;
                result.Add("spent_on", entity.SpentOn.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
                result.Add("hours", entity.Hours);
                result.Add("comments", entity.Comments);

                if (entity.CustomFields != null)
                {
                    serializer.RegisterConverters(new[] { new IssueCustomFieldConverter() });
                    result.Add("custom_fields", entity.CustomFields.ToArray());
                }

                root["time_entry"] = result;
                return root;
            }

            return result;
        }
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as IssueCategory;
            var root = new Dictionary<string, object>();
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.Add("name", entity.Name);
                result.WriteIdIfNotNull(entity.Project, "project_id");
                result.WriteIdIfNotNull(entity.AsignTo, "assigned_to_id");

                root["issue_category"] = result;
                return root;
            }

            return result;
        }
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as Issue;
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.Add(RedmineKeys.SUBJECT, entity.Subject);
                result.Add(RedmineKeys.DESCRIPTION, entity.Description);
                result.Add(RedmineKeys.NOTES, entity.Notes);
                if (entity.Id != 0)
                {
					result.Add(RedmineKeys.PRIVATE_NOTES, entity.PrivateNotes);
                }
                result.Add(RedmineKeys.IS_PRIVATE, entity.IsPrivate);
                result.WriteIdIfNotNull(entity.Project, RedmineKeys.PROJECT_ID);
                result.WriteIdIfNotNull(entity.Priority, RedmineKeys.PRIORITY_ID);
                result.WriteIdIfNotNull(entity.Status, RedmineKeys.STATUS_ID);
                result.WriteIdIfNotNull(entity.Category, RedmineKeys.CATEGORY_ID);
                result.WriteIdIfNotNull(entity.Tracker, RedmineKeys.TRACKER_ID);
                result.WriteIdIfNotNull(entity.AssignedTo, RedmineKeys.ASSIGNED_TO_ID);
                result.WriteIdIfNotNull(entity.FixedVersion, RedmineKeys.FIXED_VERSION_ID);
                result.WriteValueOrEmpty(entity.EstimatedHours, RedmineKeys.ESTIMATED_HOURS);

                result.WriteIdOrEmpty(entity.ParentIssue, RedmineKeys.PARENT_ISSUE_ID);
                result.WriteDateOrEmpty(entity.StartDate, RedmineKeys.START_DATE);
                result.WriteDateOrEmpty(entity.DueDate, RedmineKeys.DUE_DATE);
                result.WriteDateOrEmpty(entity.DueDate, RedmineKeys.UPDATED_ON);
                
				if (entity.DoneRatio != null)
                    result.Add(RedmineKeys.DONE_RATIO, entity.DoneRatio.ToString());

                result.WriteArray(RedmineKeys.UPLOADS, entity.Uploads, new UploadConverter(), serializer);
                result.WriteArray(RedmineKeys.CUSTOM_FIELDS, entity.CustomFields, new IssueCustomFieldConverter(), serializer);

                result.WriteIdsArray(RedmineKeys.WATCHER_USER_IDS, entity.Watchers);
                
                var root = new Dictionary<string, object>();
                root[RedmineKeys.ISSUE] = result;
                return root;
            }

            return result;
        }
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as IssueCategory;
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.Add(RedmineKeys.NAME, entity.Name);
                result.WriteIdIfNotNull(entity.Project,RedmineKeys.PROJECT_ID);
                result.WriteIdIfNotNull(entity.AsignTo,RedmineKeys.ASSIGNED_TO_ID);

                var root = new Dictionary<string, object>();

                root[RedmineKeys.ISSUE_CATEGORY] = result;
                return root;
            }

            return result;
        }
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as IdentifiableName;
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.WriteIdIfNotNull(entity, "id");
                if (!string.IsNullOrEmpty(entity.Name))
                    result.Add("name", entity.Name);
                return result;
            }

            return result;
        }
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as ProjectMembership;
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.WriteIdIfNotNull(entity.User, RedmineKeys.USER_ID);
                result.WriteIdsArray(RedmineKeys.ROLE_IDS, entity.Roles);

                var root = new Dictionary<string, object>();
                root[RedmineKeys.MEMBERSHIP] = result;
                return root;
            }

            return result;
        }
        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            var entity = obj as Issue;
            var root = new Dictionary<string, object>();
            var result = new Dictionary<string, object>();

            if (entity != null)
            {
                result.Add("subject", entity.Subject);
                result.Add("description", entity.Description);
                result.Add("notes", entity.Notes);
                result.WriteIdIfNotNull(entity.Project, "project_id");
                result.WriteIdIfNotNull(entity.Priority, "priority_id");
                result.WriteIdIfNotNull(entity.Status, "status_id");
                result.WriteIdIfNotNull(entity.Category, "category_id");
                result.WriteIdIfNotNull(entity.Tracker, "tracker_id");
                result.WriteIdIfNotNull(entity.AssignedTo, "assigned_to_id");
                result.WriteIdIfNotNull(entity.FixedVersion, "fixed_version_id");
               // result.WriteIdIfNotNull(entity.ParentIssue, "parent_issue_id");
                result.WriteIfNotDefaultOrNull(entity.EstimatedHours, "estimated_hours");

                if(entity.ParentIssue == null)
                    result.Add("parent_issue_id", null);
                else
                {
                    result.Add("parent_issue_id", entity.ParentIssue.Id);
                }
                if (entity.StartDate != null)
                    result.Add("start_date", entity.StartDate.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
                if (entity.DueDate != null)
                    result.Add("due_date", entity.DueDate.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));

                result.WriteIfNotDefaultOrNull(entity.DoneRatio, "done_ratio");

                if (entity.Uploads != null) result.Add("uploads", entity.Uploads.ToArray());

                if (entity.CustomFields != null)
                {
                    serializer.RegisterConverters(new[] { new IssueCustomFieldConverter() });
                    result.Add("custom_fields", entity.CustomFields.ToArray());
                }

                if (entity.Watchers != null)
                {
                    serializer.RegisterConverters(new[] { new WatcherConverter()  });
                    result.Add("watcher_user_ids", entity.Watchers.ToArray());
                }

                root["issue"] = result;
                return root;
            }

            return result;
        }