public IHttpActionResult Validate(DetailsSaveModel item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            DetailsModelContainer model;
            try
            {
                model = this.ExtractModelFromRequest(item);
            }
            catch (VeyronException ex)
            {
                this.Logger.Log(LogSeverity.Error, "Validate", ex);
                return this.Ok(new DetailsValidateResult { Success = false, Message = ex.Message, DetailsNamespace = item.DetailsNamespace });
            }

            if (model.Model == null)
            {
                return this.Ok(new DetailsValidateResult { Success = false, Message = "Item not found. Was it deleted while you were editing it?", DetailsNamespace = model.Namespace });
            }

            try {
                var result = new DetailsValidateResult { Success = true, DetailsNamespace = model.Namespace };

                var businessBase = (IBusinessBase)model.Model;
                if (!businessBase.IsValid)
                {
                    foreach (var error in businessBase.GetAllBrokenRules())
                    {
                        result.BrokenRules.Add(new BrokenRuleModel { FieldName = error.Property, Message = error.Description, Severity = error.Severity });
                    }
                }

                var props = model.Model.GetAllPropertiesForInstance();

                foreach (var prop in props.Keys)
                {                    
                    var isCalculated = prop.GetCustomAttributes(typeof(CalculatedAttribute), false).Any();
                    if (isCalculated)
                    {
                        var field = new FieldReadModel(props[prop], prop);
                        result.CalculatedFields.Add(field);
                    }

                    var backColor = FieldReadModel.GetBackColor(props[prop], prop);
                    if (backColor != null)
                    {
                        var field = new FieldBackColorModel { SystemName = prop.Name, BackColor = backColor };
                        result.FieldsBackColor.Add(field);
                    }

                    var rewriteField = new FieldReadModel(props[prop], prop);
                    if (rewriteField.CanRead)
                    {
                        result.RewriteProperties.Add(rewriteField);
                    }
                }

                return this.Ok(result);
            }
            catch (VeyronException ex)
            {
                this.Logger.Log(LogSeverity.Error, "Validate", ex);
                return this.Ok(new DetailsValidateResult { Success = false, Message = ex.Message, DetailsNamespace = model.Return(m => m.Namespace, string.Empty) });
            }
            catch (Exception ex)
            {
                this.Logger.Log(LogSeverity.Error, "Validate", ex);
                return this.Ok(new DetailsValidateResult { Success = false, Message = "An error occured. Check log files.", DetailsNamespace = model.Return(m => m.Namespace, string.Empty) });
            }
        }
        private DetailsModelContainer ExtractModelFromRequest(DetailsSaveModel detailsModel, IEditableRoot model = null)
        {
            var result = new DetailsModelContainer();

            try
           {
                result.Namespace = detailsModel.DetailsNamespace;
                result.ChildIndex = detailsModel.ChildIndex;

                if (detailsModel.Fields != null)
                {
                    detailsModel.Fields.ForEach(f => result.ChangedFields.Add(f.SystemName));
                }

                if (model == null)
                {
                    if (detailsModel.ItemId == 0)
                    {
                        var editClass = this.DynamicTypeManager.GetEditableRootType(detailsModel.ProcessSystemName);
                        result.Model = (IEditableRoot)MethodCaller.CallFactoryMethod(editClass, string.Format(CultureInfo.InvariantCulture, "New{0}", detailsModel.ProcessSystemName), new object[0]);
                    }
                    else
                    {
                        result.Model = this.DynamicTypeManager.GetEditableRoot<IEditableRoot>(detailsModel.ProcessSystemName, detailsModel.ItemId);
                    }
                }
                else
                {
                    result.Model = model;
                }

                if (result.Model == null)
                {
                    return result;
                }
                
                //System.Reflection.MethodInfo dynMethod = result.Model.GetType().GetMethod("UpdateCalculatedFields", BindingFlags.NonPublic | BindingFlags.Instance);
                //if (dynMethod != null)
                //    dynMethod.Invoke(result.Model, new object[] { });

              

                if (detailsModel.Fields != null)
                {
                    foreach (var field in detailsModel.Fields)
                    {
                        var fullName = string.Join(".", result.Model.GetFullPropertyPath(field.SystemName));

                        var property = result.Model.GetPropertyByFullName(fullName);
                        var propertyModel = result.Model.GetAncestor(property);

                        if (field.FieldType == ColumnTypes.DisplayList
                            || field.FieldType == ColumnTypes.ReverseReference
                            || field.FieldType == ColumnTypes.ReverseMultiReference
                            || field.FieldType == ColumnTypes.AuditTrail
                            || field.FieldType == ColumnTypes.Approval
                            || field.FieldType == ColumnTypes.File)
                        {
                            continue;
                        }

                        if (field.FieldType == ColumnTypes.Image)
                        {
                            var imageContent = field.Value as string;
                            if (!string.IsNullOrEmpty(imageContent))
                            {
                                field.Value = Convert.FromBase64String(imageContent);
                            }
                        }
                        else if (field.FieldType == ColumnTypes.Result)
                        {
                            if (field.Value != null)
                            {
                                var resultContent = JsonConvert.DeserializeObject<ResultValueModel>((string)field.Value);
                                if (resultContent != null)
                                {
                                    using (new BypassPropertyCheckContext())
                                    {
                                        propertyModel.SetValueByPropertyName(field.SystemName, resultContent.Score);
                                        var currentResultListValue = (MobileObservableCollection<ChoiceInfo>)propertyModel.GetValueByPropertyName(string.Format(CultureInfo.InvariantCulture, "{0}{1}", field.SystemName, Constants.ResultListPostfix));
                                        if (currentResultListValue != null)
                                        {
                                            foreach (var choiceInfo in currentResultListValue)
                                            {
                                                if (choiceInfo.Score == resultContent.Score)
                                                {
                                                    choiceInfo.NewItemProcessId = resultContent.NewItemProcessId ?? 0;
                                                    break;
                                                }
                                            }
                                        }

                                        ResultFieldHelper.SetChoiceList(propertyModel, currentResultListValue);
                                    }

                                    continue;
                                }
                            }

                            using (new BypassPropertyCheckContext())
                            {
                                propertyModel.SetValueByPropertyName(field.SystemName, 0.0);
                            }

                            continue;
                        }
                        else if (field.FieldType == ColumnTypes.MultiReference)
                        {
                            var currentMcrValue = (ICrossRefItemList)result.Model.GetValueByPropertyName(field.SystemName);

                            if (field.Value == null)
                            {
                                currentMcrValue.Clear();
                                continue;
                            }

                            var mcrContent = JsonConvert.DeserializeObject<int[]>((string)field.Value);
                            if (mcrContent == null || mcrContent.Length == 0)
                            {
                                if (currentMcrValue != null)
                                {
                                    currentMcrValue.Clear();
                                }
                                continue;
                            }


                            var newItemsList =
                                mcrContent.Where(mcrItem => !currentMcrValue.Contains(mcrItem)).Select(id => (ICrossRefItemInfo)this.DynamicTypeManager.GetMultiCrossReferenceItem(propertyModel.ProcessName, field.SystemName, id)).ToList();

                            var deletedItems = (from ICrossRefItemInfo item in currentMcrValue where !mcrContent.Contains(item.Id) select item).ToList();

                            currentMcrValue.RemoveRange(deletedItems);
                            currentMcrValue.AddRange(newItemsList);
                            continue;
                        }
                        else if (field.FieldType == ColumnTypes.Checklist)
                        {
                            var json = (string)field.Value;
                            var items = JsonConvert.DeserializeObject<DetailsSaveModel[]>(json);
                            var currentChecklistValue = (ChecklistEdit)result.Model.GetValueByPropertyName(field.SystemName);

                            // extract models for each details item in checklist
                            var answers = new List<DetailsModelContainer>();
                            foreach (var item in items)
                            {
                                // we have to check, if this is new item (item we are extracting) and it has corresponding child element in current (unmodified, loaded from db) checklist value 
                                // we should pass it as model.
                                // if we do not do this, we will loose some fields values (fields, filled by Mapping setup in Checklist for just saved checklist process, for example).
                                IEditableRoot childModel = null;
                                if (item.ItemId == 0)
                                {
                                    if (item.ChildIndex < currentChecklistValue.AnswerProcessList.Count && ((IEditableRoot)currentChecklistValue.AnswerProcessList[item.ChildIndex]).Id == 0)
                                    {
                                        childModel = (IEditableRoot)currentChecklistValue.AnswerProcessList[item.ChildIndex];
                                    }
                                }
                                else
                                {
                                    childModel = currentChecklistValue.AnswerProcessList.Cast<IEditableRoot>().FirstOrDefault(i => i.Id == item.ItemId);
                                }

                                answers.Add(this.ExtractModelFromRequest(item, childModel));
                            }

                            if (answers.IsNullOrEmpty())
                            {
                                continue;
                            }

                            var newItemsList = answers.Where(item => item.Model.Id != 0 && currentChecklistValue.AnswerProcessList.Cast<IEditableRoot>().All(i => i.Id != item.Model.Id)).ToList();
                            var deletedItemsList = (from IDynamicObject item in currentChecklistValue.AnswerProcessList where item.Id != 0 && !answers.Exists(i => i.Model.Id == item.Id) select item).ToList();
                            var changedItemsList = answers.Where(item => item.Model.Id != 0 && currentChecklistValue.AnswerProcessList.Cast<IEditableRoot>().Any(i => i.Id == item.Model.Id)).ToList();

                            for (int i = 0; i < answers.Count; i++)
                            {
                                try
                                {
                                    var answer = answers[i];
                                    if (answer.Model.Id != 0)
                                    {
                                        continue;
                                    }

                                    if (currentChecklistValue.AnswerProcessList.Count < answer.ChildIndex || ((IEditableRoot)currentChecklistValue.AnswerProcessList[answer.ChildIndex]).Id != 0)
                                    {
                                        newItemsList.Add(answer);
                                    }
                                    else
                                    {
                                        var oldItem = (IEditableRoot)currentChecklistValue.AnswerProcessList[answer.ChildIndex];
                                        if (ReferenceEquals(oldItem, answer.Model))
                                        {
                                            continue;
                                        }

                                        var properties = oldItem.GetAllPropertiesForInstance();
                                        foreach (var oldAnswerProperty in properties.Where(p => answer.ChangedFields.Contains(p.Key.Name)))
                                        {
                                            if (oldAnswerProperty.Key.CanWrite && oldAnswerProperty.Value.CanWriteProperty(oldAnswerProperty.Key.Name))
                                            {
                                                using (new BypassPropertyCheckContext())
                                                {
                                                    oldAnswerProperty.Value.SetValueByPropertyName(oldAnswerProperty.Key.Name, (object)answer.Model.GetValueByPropertyName(oldAnswerProperty.Key.Name));
                                                }
                                            }
                                        }
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Logger.Log(LogSeverity.Error, "ProcessController", ex);
                                    Debugger.Break();
                                }
                            }

                            foreach (var answer in deletedItemsList)
                            {
                                currentChecklistValue.AnswerProcessList.Remove(answer);
                            }

                            foreach (var answer in newItemsList)
                            {
                                answer.Model.MakeChild();
                                currentChecklistValue.AnswerProcessList.Add(answer.Model);
                            }

                            foreach (var answer in changedItemsList)
                            {
                                IEditableRoot answer1 = answer.Model;
                                var oldAnswer = (IEditableRoot)currentChecklistValue.AnswerProcessList.FindFirst(i => i, v => v.Id == answer1.Id);
                                if (ReferenceEquals(oldAnswer, answer.Model))
                                {
                                    continue;
                                }

                                var properties = oldAnswer.GetAllPropertiesForInstance();
                                foreach (var oldAnswerProperty in properties.Where(p => answer.ChangedFields.Contains(p.Key.Name) || p.Key.GetCustomAttributes(typeof(FieldEditorAttribute), false).Cast<FieldEditorAttribute>().Any(f => f.DataType == Constants.ChoiceFieldType)))
                                {
                                    if (oldAnswerProperty.Key.CanWrite && oldAnswerProperty.Value.CanWriteProperty(oldAnswerProperty.Key.Name))
                                    {
                                        using (new BypassPropertyCheckContext())
                                        {
                                            try
                                            {
                                                oldAnswerProperty.Value.SetValueByPropertyName(oldAnswerProperty.Key.Name, (object)answer.Model.GetValueByPropertyName(oldAnswerProperty.Key.Name));
                                            }
                                            catch (Exception ex)
                                            {
                                                Debug.WriteLine(ex.Message);
                                                Debugger.Break();
                                            }
                                        }
                                    }
                                }
                            }

                            continue;
                        }
                        else if (field.FieldType == ColumnTypes.Sample)
                        {
                            var currentSampleValue = (ISampleList)result.Model.GetValueByPropertyName(field.SystemName);

                            var sampleContent = JsonConvert.DeserializeObject<SampleModel[]>((string)field.Value);
                            if (sampleContent == null || sampleContent.Length == 0)
                            {
                                currentSampleValue.Clear();
                                continue;
                            }

                            var samples = new List<ISampleEdit>();
                            foreach (var item in sampleContent)
                            {
                                ISampleEdit childModel = null;
                                if (item.Id == 0)
                                {
                                    if (item.ChildIndex < currentSampleValue.Count && ((ISampleEdit)currentSampleValue[item.ChildIndex]).Id == 0)
                                    {
                                        childModel = (ISampleEdit)currentSampleValue[item.ChildIndex];
                                    }
                                    else
                                    {
                                        currentSampleValue.AddSample(result.Model.Id);
                                        childModel = (ISampleEdit)currentSampleValue[currentSampleValue.Count - 1];
                                    }
                                }
                                else
                                {
                                    childModel = currentSampleValue.Cast<ISampleEdit>().FirstOrDefault(i => i.Id == item.Id);
                                }

                                ExtractSample(item, childModel);
                                samples.Add(childModel);
                            }

                            if (samples.IsNullOrEmpty())
                            {
                                continue;
                            }

                            var deletedItemsList = (from IDynamicObject item in currentSampleValue where item.Id != 0 && sampleContent.All(i => i.Id != item.Id) select item).ToList();

                            foreach (var answer in deletedItemsList)
                            {
                                currentSampleValue.Remove(answer);
                            }

                            continue;
                        }
                        else if (field.FieldType == ColumnTypes.SampleType)
                        {
                            if (field.Value != null)
                            {
                                var sampleTypeContent = JsonConvert.DeserializeObject<SampleTypeValueModel>((string)field.Value);
                                if (sampleTypeContent != null)
                                {
                                    using (new BypassPropertyCheckContext())
                                    {
                                        propertyModel.SetValueByPropertyName(field.SystemName, sampleTypeContent.SampleType);
                                        propertyModel.SetValueByPropertyName(field.SystemName + Constants.SampleTrueLabel, sampleTypeContent.TrueLabel);
                                        propertyModel.SetValueByPropertyName(field.SystemName + Constants.SampleFalseLabel, sampleTypeContent.FalseLabel);
                                    }

                                    continue;
                                }
                            }

                            using (new BypassPropertyCheckContext())
                            {
                                propertyModel.SetValueByPropertyName(field.SystemName, SampleTypes.Number.ToString());
                            }

                            continue;
                        }

                        using (new BypassPropertyCheckContext()) // workaround
                        {
                            try
                            {
                                propertyModel.SetValueByPropertyName(field.SystemName, SafeTypeConverter.Convert(field.Value, result.Model.GetPropertyByName(field.SystemName).PropertyType));
                            }
                            catch (Exception ex)
                            {
                                Debug.WriteLine(ex.Message);
                                Debugger.Break();
                            }
                        }
                    }
                }

                if (detailsModel.NextStateGuid != null)
                {
                    var supportStates = result.Model as ISupportStates;
                    if (supportStates != null && (supportStates.CurrentStateGuid != detailsModel.NextStateGuid.Value))
                    {
                        var nextState = supportStates.GetNextAvailableStates().FirstOrDefault(s => s.Guid == detailsModel.NextStateGuid.Value);
                        if (nextState != null)
                        {
                            supportStates.CurrentState = nextState.Id;
                        }
                        else
                        {
                            throw new VeyronException("Selected next state is not available for current item state. Was item modified while you were editing it?");
                        }
                    }
                }

                UpdateModelDefaultValues(result.Model);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                throw;
            }

            return result;
        }
        public IHttpActionResult Save(DetailsSaveModel item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            DetailsModelContainer model;
            try
            {
                model = this.ExtractModelFromRequest(item);
            }
            catch (VeyronException ex)
            {
                this.Logger.Log(LogSeverity.Error, "Save", ex);
                return this.Ok(new DetailsSaveResult { Success = false, Message = ex.Message, DetailsNamespace = item.DetailsNamespace });
            }

            if (model.Model == null)
            {
                return this.Ok(new DetailsSaveResult { Success = false, Message = "Item not found. Was it deleted while you were editing it?", DetailsNamespace = model.Namespace });
            }

            var businessBase = (IBusinessBase)model.Model;
            if (!businessBase.IsValid)
            {
                var result = new DetailsSaveResult { Success = false, Message = businessBase.Error, DetailsNamespace = model.Namespace };
                foreach (var error in businessBase.GetAllBrokenRules())
                {
                    result.BrokenRules.Add(new BrokenRuleModel { FieldName = error.Property, Message = error.Description, Severity = error.Severity });
                }

                return this.Ok(result);
            }

            IEditableRoot newModel;
            try
            {
                newModel = (IEditableRoot)businessBase.Save();
            }
            catch (DataPortalException ex)
            {
                var indexViolation = ex.BusinessException as UniqueIndexViolationException;
                if (indexViolation != null)
                {
                    var message = new StringBuilder();
                    var uniqueIndexError = JsonConvert.DeserializeObject<MobileList<UniqueIndexViolationError>>(indexViolation.Message, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });

                    foreach (var uniqueIndexViolationError in uniqueIndexError)
                    {
                        message.AppendLine();
                        message.AppendFormat(
                            CultureInfo.InvariantCulture,
                            LanguageService.Translate("Error_UniqueDataIndexViolation"),
                            uniqueIndexViolationError.IndexName,
                            string.Join(",", uniqueIndexViolationError.IndexFields.Select(x => model.Model.GetPropertyDisplayName(x) ?? x)),
                            uniqueIndexViolationError.ViolationMessage);
                    }

                    return this.Ok(new DetailsSaveResult { Success = false, Message = message.ToString(), DetailsNamespace = model.Namespace });
                }

                return this.Ok(new DetailsSaveResult { Success = false, Message = ex.ToString(), DetailsNamespace = model.Namespace });
            }
            catch (Exception ex)
            {
                return this.Ok(new DetailsSaveResult { Success = false, Message = ex.ToString(), DetailsNamespace = model.Namespace });
            }

            try
            {
                return this.Ok(new DetailsSaveResult { Success = true, ItemId = newModel.Id, DetailsNamespace = model.Namespace, Model = CreateDetailsReadModel(newModel) });
            }
            catch (Exception ex)
            {
                return this.Ok(new DetailsSaveResult { Success = false, Message = ex.ToString(), DetailsNamespace = model.Namespace });
            }
        }